diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml
new file mode 100644
index 000000000..2369cf79e
--- /dev/null
+++ b/.github/workflows/cd.yml
@@ -0,0 +1,100 @@
+name: Continuous Deployment
+on:
+ schedule:
+ - cron: '15 4 * * *'
+ workflow_dispatch:
+
+jobs:
+
+ # Windows
+ package-windows-editor:
+ name: Editor (Windows)
+ runs-on: "windows-latest"
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@v2
+ - name: Checkout LFS
+ run: |
+ git lfs version
+ git lfs pull
+ - name: Build
+ run: |
+ .\PackageEditor.bat -arch=x64 -platform=Windows -deployOutput=Output
+ - name: Upload
+ uses: actions/upload-artifact@v2
+ with:
+ name: Windows-Editor
+ path: Output/Editor.zip
+ - name: Upload
+ uses: actions/upload-artifact@v2
+ with:
+ name: Windows-EditorDebugSymbols
+ path: Output/EditorDebugSymbols.zip
+ package-windows-game:
+ name: Game (Windows)
+ runs-on: "windows-latest"
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@v2
+ - name: Checkout LFS
+ run: |
+ git lfs version
+ git lfs pull
+ - name: Build
+ run: |
+ .\PackagePlatforms.bat -arch=x64 -platform=Windows -deployOutput=Output
+ - name: Upload
+ uses: actions/upload-artifact@v2
+ with:
+ name: Windows-Game
+ path: Output/Windows.zip
+
+ # Linux
+ package-linux-editor:
+ name: Editor (Linux)
+ runs-on: "ubuntu-20.04"
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@v2
+ - name: Checkout LFS
+ run: |
+ git lfs version
+ git lfs pull
+ - name: Install dependencies
+ run: |
+ sudo rm -f /etc/apt/sources.list.d/*
+ sudo cp -f .github/workflows/build_linux_sources.list /etc/apt/sources.list
+ sudo apt-get update
+ sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
+ - name: Build
+ run: |
+ ./PackageEditor.sh -arch=x64 -platform=Linux -deployOutput=Output
+ - name: Upload
+ uses: actions/upload-artifact@v2
+ with:
+ name: Linux-Editor
+ path: Output/FlaxEditorLinux.zip
+ package-linux-game:
+ name: Game (Linux)
+ runs-on: "ubuntu-20.04"
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@v2
+ - name: Checkout LFS
+ run: |
+ git lfs version
+ git lfs pull
+ - name: Install dependencies
+ run: |
+ sudo rm -f /etc/apt/sources.list.d/*
+ sudo cp -f .github/workflows/build_linux_sources.list /etc/apt/sources.list
+ sudo apt-get update
+ sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
+ - name: Build
+ run: |
+ ./PackagePlatforms.sh -arch=x64 -platform=Linux -deployOutput=Output
+ - name: Upload
+ uses: actions/upload-artifact@v2
+ with:
+ name: Linux-Game
+ path: Output/Linux.zip
diff --git a/Source/Editor/Content/Items/AssetItem.cs b/Source/Editor/Content/Items/AssetItem.cs
index afb68d42a..f534e93eb 100644
--- a/Source/Editor/Content/Items/AssetItem.cs
+++ b/Source/Editor/Content/Items/AssetItem.cs
@@ -108,6 +108,26 @@ namespace FlaxEditor.Content
return false;
}
+ ///
+ /// Called when user dags this item into editor viewport or scene tree node.
+ ///
+ /// The editor context (eg. editor viewport or scene tree node).
+ /// True if item can be dropped in, otherwise false.
+ public virtual bool OnEditorDrag(object context)
+ {
+ return false;
+ }
+
+ ///
+ /// Called when user drops the item into editor viewport or scene tree node.
+ ///
+ /// The editor context (eg. editor viewport or scene tree node).
+ /// The spawned object.
+ public virtual Actor OnEditorDrop(object context)
+ {
+ throw new NotSupportedException($"Asset {GetType()} doesn't support dropping into viewport.");
+ }
+
///
protected override bool DrawShadow => true;
diff --git a/Source/Editor/Content/Items/BinaryAssetItem.cs b/Source/Editor/Content/Items/BinaryAssetItem.cs
index 417bd23e4..2503e9a38 100644
--- a/Source/Editor/Content/Items/BinaryAssetItem.cs
+++ b/Source/Editor/Content/Items/BinaryAssetItem.cs
@@ -103,14 +103,26 @@ namespace FlaxEditor.Content
/// Implementation of for assets.
///
///
- public class ModelAssetItem : BinaryAssetItem
+ public class ModelItem : BinaryAssetItem
{
///
- public ModelAssetItem(string path, ref Guid id, string typeName, Type type)
+ public ModelItem(string path, ref Guid id, string typeName, Type type)
: base(path, ref id, typeName, type, ContentItemSearchFilter.Model)
{
}
+ ///
+ public override bool OnEditorDrag(object context)
+ {
+ return true;
+ }
+
+ ///
+ public override Actor OnEditorDrop(object context)
+ {
+ return new StaticModel { Model = FlaxEngine.Content.LoadAsync(ID) };
+ }
+
///
protected override void OnBuildTooltipText(StringBuilder sb)
{
@@ -142,14 +154,26 @@ namespace FlaxEditor.Content
/// Implementation of for assets.
///
///
- public class SkinnedModelAssetItem : BinaryAssetItem
+ public class SkinnedModeItem : BinaryAssetItem
{
///
- public SkinnedModelAssetItem(string path, ref Guid id, string typeName, Type type)
+ public SkinnedModeItem(string path, ref Guid id, string typeName, Type type)
: base(path, ref id, typeName, type, ContentItemSearchFilter.Model)
{
}
+ ///
+ public override bool OnEditorDrag(object context)
+ {
+ return true;
+ }
+
+ ///
+ public override Actor OnEditorDrop(object context)
+ {
+ return new AnimatedModel { SkinnedModel = FlaxEngine.Content.LoadAsync(ID) };
+ }
+
///
protected override void OnBuildTooltipText(StringBuilder sb)
{
diff --git a/Source/Editor/Content/Items/PrefabItem.cs b/Source/Editor/Content/Items/PrefabItem.cs
index aee264d55..e758595ae 100644
--- a/Source/Editor/Content/Items/PrefabItem.cs
+++ b/Source/Editor/Content/Items/PrefabItem.cs
@@ -21,6 +21,18 @@ namespace FlaxEditor.Content
{
}
+ ///
+ public override bool OnEditorDrag(object context)
+ {
+ return true;
+ }
+
+ ///
+ public override Actor OnEditorDrop(object context)
+ {
+ return PrefabManager.SpawnPrefab(FlaxEngine.Content.LoadAsync(ID), null);
+ }
+
///
public override ContentItemType ItemType => ContentItemType.Asset;
diff --git a/Source/Editor/Content/Items/VisualScriptItem.cs b/Source/Editor/Content/Items/VisualScriptItem.cs
index 04311644b..c1ccf5d73 100644
--- a/Source/Editor/Content/Items/VisualScriptItem.cs
+++ b/Source/Editor/Content/Items/VisualScriptItem.cs
@@ -538,6 +538,18 @@ namespace FlaxEditor.Content
Editor.Instance.CodeEditing.ClearTypes();
}
+ ///
+ public override bool OnEditorDrag(object context)
+ {
+ return new ScriptType(typeof(Actor)).IsAssignableFrom(ScriptType) && ScriptType.CanCreateInstance;
+ }
+
+ ///
+ public override Actor OnEditorDrop(object context)
+ {
+ return (Actor)ScriptType.CreateInstance();
+ }
+
///
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.VisualScript128;
diff --git a/Source/Editor/Content/Proxy/AudioClipProxy.cs b/Source/Editor/Content/Proxy/AudioClipProxy.cs
index ba60d6ef9..ceff22dd1 100644
--- a/Source/Editor/Content/Proxy/AudioClipProxy.cs
+++ b/Source/Editor/Content/Proxy/AudioClipProxy.cs
@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
+using System.Text;
using FlaxEditor.Content.Thumbnails;
using FlaxEditor.Viewport.Previews;
using FlaxEditor.Windows;
@@ -11,11 +12,51 @@ using FlaxEngine.GUI;
namespace FlaxEditor.Content
{
+ ///
+ /// Implementation of for assets.
+ ///
+ ///
+ class AudioClipItem : BinaryAssetItem
+ {
+ ///
+ public AudioClipItem(string path, ref Guid id, string typeName, Type type)
+ : base(path, ref id, typeName, type, ContentItemSearchFilter.Audio)
+ {
+ }
+
+ ///
+ public override bool OnEditorDrag(object context)
+ {
+ return true;
+ }
+
+ ///
+ public override Actor OnEditorDrop(object context)
+ {
+ return new AudioSource { Clip = FlaxEngine.Content.LoadAsync(ID) };
+ }
+
+ ///
+ protected override void OnBuildTooltipText(StringBuilder sb)
+ {
+ base.OnBuildTooltipText(sb);
+
+ var asset = FlaxEngine.Content.Load(ID, 100);
+ if (asset)
+ {
+ var info = asset.Info;
+ sb.Append("Duration: ").Append(asset.Length).AppendLine();
+ sb.Append("Channels: ").Append(info.NumChannels).AppendLine();
+ sb.Append("Bit Depth: ").Append(info.BitDepth).AppendLine();
+ }
+ }
+ }
+
///
/// A asset proxy object.
///
///
- public class AudioClipProxy : BinaryAssetProxy
+ class AudioClipProxy : BinaryAssetProxy
{
private List _previews;
@@ -34,6 +75,12 @@ namespace FlaxEditor.Content
return new AudioClipWindow(editor, (AssetItem)item);
}
+ ///
+ public override AssetItem ConstructItem(string path, string typeName, ref Guid id)
+ {
+ return new AudioClipItem(path, ref id, typeName, AssetType);
+ }
+
///
public override Color AccentColor => Color.FromRGB(0xB3452B);
diff --git a/Source/Editor/Content/Proxy/BinaryAssetProxy.cs b/Source/Editor/Content/Proxy/BinaryAssetProxy.cs
index 4d27f325b..d19f8fd63 100644
--- a/Source/Editor/Content/Proxy/BinaryAssetProxy.cs
+++ b/Source/Editor/Content/Proxy/BinaryAssetProxy.cs
@@ -47,9 +47,9 @@ namespace FlaxEditor.Content
if (typeof(TextureBase).IsAssignableFrom(type))
return new TextureAssetItem(path, ref id, typeName, type);
if (typeof(Model).IsAssignableFrom(type))
- return new ModelAssetItem(path, ref id, typeName, type);
+ return new ModelItem(path, ref id, typeName, type);
if (typeof(SkinnedModel).IsAssignableFrom(type))
- return new SkinnedModelAssetItem(path, ref id, typeName, type);
+ return new SkinnedModeItem(path, ref id, typeName, type);
ContentItemSearchFilter searchFilter;
if (typeof(MaterialBase).IsAssignableFrom(type))
@@ -58,11 +58,9 @@ namespace FlaxEditor.Content
searchFilter = ContentItemSearchFilter.Prefab;
else if (typeof(SceneAsset).IsAssignableFrom(type))
searchFilter = ContentItemSearchFilter.Scene;
- else if (typeof(AudioClip).IsAssignableFrom(type))
- searchFilter = ContentItemSearchFilter.Audio;
else if (typeof(Animation).IsAssignableFrom(type))
searchFilter = ContentItemSearchFilter.Animation;
- else if (typeof(ParticleEmitter).IsAssignableFrom(type) || typeof(ParticleSystem).IsAssignableFrom(type))
+ else if (typeof(ParticleEmitter).IsAssignableFrom(type))
searchFilter = ContentItemSearchFilter.Particles;
else
searchFilter = ContentItemSearchFilter.Other;
diff --git a/Source/Editor/Content/Proxy/CollisionDataProxy.cs b/Source/Editor/Content/Proxy/CollisionDataProxy.cs
index c23730375..e7d437adc 100644
--- a/Source/Editor/Content/Proxy/CollisionDataProxy.cs
+++ b/Source/Editor/Content/Proxy/CollisionDataProxy.cs
@@ -8,11 +8,36 @@ using FlaxEngine;
namespace FlaxEditor.Content
{
+ ///
+ /// Implementation of for assets.
+ ///
+ ///
+ class CollisionDataItem : BinaryAssetItem
+ {
+ ///
+ public CollisionDataItem(string path, ref Guid id, string typeName, Type type)
+ : base(path, ref id, typeName, type, ContentItemSearchFilter.Other)
+ {
+ }
+
+ ///
+ public override bool OnEditorDrag(object context)
+ {
+ return true;
+ }
+
+ ///
+ public override Actor OnEditorDrop(object context)
+ {
+ return new MeshCollider { CollisionData = FlaxEngine.Content.LoadAsync(ID) };
+ }
+ }
+
///
/// A asset proxy object.
///
///
- public class CollisionDataProxy : BinaryAssetProxy
+ class CollisionDataProxy : BinaryAssetProxy
{
///
public override string Name => "Collision Data";
@@ -23,6 +48,12 @@ namespace FlaxEditor.Content
return new CollisionDataWindow(editor, item as AssetItem);
}
+ ///
+ public override AssetItem ConstructItem(string path, string typeName, ref Guid id)
+ {
+ return new CollisionDataItem(path, ref id, typeName, AssetType);
+ }
+
///
public override Color AccentColor => Color.FromRGB(0x2c3e50);
diff --git a/Source/Editor/Content/Proxy/ModelProxy.cs b/Source/Editor/Content/Proxy/ModelProxy.cs
index a28a022a8..2baf717e1 100644
--- a/Source/Editor/Content/Proxy/ModelProxy.cs
+++ b/Source/Editor/Content/Proxy/ModelProxy.cs
@@ -47,7 +47,7 @@ namespace FlaxEditor.Content
menu.AddButton("Create collision data", () =>
{
- var model = FlaxEngine.Content.LoadAsync(((ModelAssetItem)item).ID);
+ var model = FlaxEngine.Content.LoadAsync(((ModelItem)item).ID);
var collisionDataProxy = (CollisionDataProxy)Editor.Instance.ContentDatabase.GetProxy();
collisionDataProxy.CreateCollisionDataFromModel(model);
});
diff --git a/Source/Editor/Content/Proxy/ParticleSystemProxy.cs b/Source/Editor/Content/Proxy/ParticleSystemProxy.cs
index f3b2eb67a..7e206fba9 100644
--- a/Source/Editor/Content/Proxy/ParticleSystemProxy.cs
+++ b/Source/Editor/Content/Proxy/ParticleSystemProxy.cs
@@ -10,6 +10,31 @@ using FlaxEngine.GUI;
namespace FlaxEditor.Content
{
+ ///
+ /// Implementation of for assets.
+ ///
+ ///
+ class ParticleSystemItem : BinaryAssetItem
+ {
+ ///
+ public ParticleSystemItem(string path, ref Guid id, string typeName, Type type)
+ : base(path, ref id, typeName, type, ContentItemSearchFilter.Particles)
+ {
+ }
+
+ ///
+ public override bool OnEditorDrag(object context)
+ {
+ return true;
+ }
+
+ ///
+ public override Actor OnEditorDrop(object context)
+ {
+ return new ParticleEffect { ParticleSystem = FlaxEngine.Content.LoadAsync(ID) };
+ }
+ }
+
///
/// A asset proxy object.
///
@@ -28,6 +53,12 @@ namespace FlaxEditor.Content
return new ParticleSystemWindow(editor, item as AssetItem);
}
+ ///
+ public override AssetItem ConstructItem(string path, string typeName, ref Guid id)
+ {
+ return new ParticleSystemItem(path, ref id, typeName, AssetType);
+ }
+
///
public override Color AccentColor => Color.FromRGB(0xFF790200);
diff --git a/Source/Editor/Content/Proxy/SceneAnimationProxy.cs b/Source/Editor/Content/Proxy/SceneAnimationProxy.cs
index 83d9247d8..66c1bfff2 100644
--- a/Source/Editor/Content/Proxy/SceneAnimationProxy.cs
+++ b/Source/Editor/Content/Proxy/SceneAnimationProxy.cs
@@ -7,6 +7,31 @@ using FlaxEngine;
namespace FlaxEditor.Content
{
+ ///
+ /// Implementation of for assets.
+ ///
+ ///
+ class SceneAnimationItem : BinaryAssetItem
+ {
+ ///
+ public SceneAnimationItem(string path, ref Guid id, string typeName, Type type)
+ : base(path, ref id, typeName, type, ContentItemSearchFilter.Other)
+ {
+ }
+
+ ///
+ public override bool OnEditorDrag(object context)
+ {
+ return true;
+ }
+
+ ///
+ public override Actor OnEditorDrop(object context)
+ {
+ return new SceneAnimationPlayer { Animation = FlaxEngine.Content.LoadAsync(ID) };
+ }
+ }
+
///
/// A asset proxy object.
///
@@ -22,6 +47,12 @@ namespace FlaxEditor.Content
return new SceneAnimationWindow(editor, item as AssetItem);
}
+ ///
+ public override AssetItem ConstructItem(string path, string typeName, ref Guid id)
+ {
+ return new SceneAnimationItem(path, ref id, typeName, AssetType);
+ }
+
///
public override Color AccentColor => Color.FromRGB(0xff5c4a87);
diff --git a/Source/Editor/Editor.cpp b/Source/Editor/Editor.cpp
index 2284478dd..1b18034c4 100644
--- a/Source/Editor/Editor.cpp
+++ b/Source/Editor/Editor.cpp
@@ -518,7 +518,7 @@ bool Editor::Init()
exit(failed ? 1 : 0);
return true;
}
-
+
// If during last lightmaps baking engine crashed we could try to restore the progress
ShadowsOfMordor::Builder::Instance()->CheckIfRestoreState();
@@ -534,6 +534,12 @@ bool Editor::Init()
// Initialize managed editor
Managed->Init();
+ // Start play if requested by cmd line
+ if (CommandLine::Options.Play.HasValue())
+ {
+ Managed->RequestStartPlayOnEditMode();
+ }
+
return false;
}
diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs
index adf4d566b..e7b33852b 100644
--- a/Source/Editor/Editor.cs
+++ b/Source/Editor/Editor.cs
@@ -46,6 +46,7 @@ namespace FlaxEditor
private bool _isAfterInit, _areModulesInited, _areModulesAfterInitEnd, _isHeadlessMode;
private string _projectToOpen;
private float _lastAutoSaveTimer;
+ private Guid _startupSceneCmdLine;
private const string ProjectDataLastScene = "LastScene";
private const string ProjectDataLastSceneSpawn = "LastSceneSpawn";
@@ -271,10 +272,11 @@ namespace FlaxEditor
module.OnEndInit();
}
- internal void Init(bool isHeadless, bool skipCompile)
+ internal void Init(bool isHeadless, bool skipCompile, Guid startupScene)
{
EnsureState();
_isHeadlessMode = isHeadless;
+ _startupSceneCmdLine = startupScene;
Log("Editor init");
if (isHeadless)
Log("Running in headless mode");
@@ -332,6 +334,17 @@ namespace FlaxEditor
}
// Load scene
+
+ // scene cmd line argument
+ var scene = ContentDatabase.Find(_startupSceneCmdLine);
+ if (scene is SceneItem)
+ {
+ Editor.Log("Loading scene specified in command line");
+ Scene.OpenScene(_startupSceneCmdLine);
+ return;
+ }
+
+ // if no scene cmd line argument is provided
var startupSceneMode = Options.Options.General.StartupSceneMode;
if (startupSceneMode == GeneralOptions.StartupSceneModes.LastOpened && !ProjectCache.HasCustomData(ProjectDataLastScene))
{
@@ -1309,6 +1322,19 @@ namespace FlaxEditor
AnimGraphDebugFlow?.Invoke(debugFlow);
}
+ private static void RequestStartPlayOnEditMode()
+ {
+ if (Instance.StateMachine.IsEditMode)
+ Instance.Simulation.RequestStartPlay();
+ if (Instance.StateMachine.IsPlayMode)
+ Instance.StateMachine.StateChanged -= RequestStartPlayOnEditMode;
+ }
+
+ internal static void Internal_RequestStartPlayOnEditMode()
+ {
+ Instance.StateMachine.StateChanged += RequestStartPlayOnEditMode;
+ }
+
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern int Internal_ReadOutputLogs(string[] outMessages, byte[] outLogTypes, long[] outLogTimes);
diff --git a/Source/Editor/Managed/ManagedEditor.cpp b/Source/Editor/Managed/ManagedEditor.cpp
index 35219a906..18a905d4b 100644
--- a/Source/Editor/Managed/ManagedEditor.cpp
+++ b/Source/Editor/Managed/ManagedEditor.cpp
@@ -35,6 +35,7 @@ MMethod* Internal_GetGameWindowSize = nullptr;
MMethod* Internal_OnAppExit = nullptr;
MMethod* Internal_OnVisualScriptingDebugFlow = nullptr;
MMethod* Internal_OnAnimGraphDebugFlow = nullptr;
+MMethod* Internal_RequestStartPlayOnEditMode = nullptr;
void OnLightmapsBake(ShadowsOfMordor::BuildProgressStep step, float stepProgress, float totalProgress, bool isProgressEvent)
{
@@ -209,7 +210,7 @@ ManagedEditor::~ManagedEditor()
void ManagedEditor::Init()
{
// Note: editor modules should perform quite fast init, any longer things should be done in async during 'editor splash screen time
- void* args[2];
+ void* args[3];
MClass* mclass = GetClass();
if (mclass == nullptr)
{
@@ -230,6 +231,12 @@ void ManagedEditor::Init()
bool skipCompile = CommandLine::Options.SkipCompile.IsTrue();
args[0] = &isHeadless;
args[1] = &skipCompile;
+ Guid sceneId;
+ if (!CommandLine::Options.Play.HasValue() || (CommandLine::Options.Play.HasValue() && Guid::Parse(CommandLine::Options.Play.GetValue(), sceneId)))
+ {
+ sceneId = Guid::Empty;
+ }
+ args[2] = &sceneId;
initMethod->Invoke(instance, args, &exception);
if (exception)
{
@@ -481,6 +488,18 @@ bool ManagedEditor::OnAppExit()
return MUtils::Unbox(Internal_OnAppExit->Invoke(GetManagedInstance(), nullptr, nullptr));
}
+void ManagedEditor::RequestStartPlayOnEditMode()
+{
+ if (!HasManagedInstance())
+ return;
+ if (Internal_RequestStartPlayOnEditMode == nullptr)
+ {
+ Internal_RequestStartPlayOnEditMode = GetClass()->GetMethod("Internal_RequestStartPlayOnEditMode");
+ ASSERT(Internal_RequestStartPlayOnEditMode);
+ }
+ Internal_RequestStartPlayOnEditMode->Invoke(GetManagedInstance(), nullptr, nullptr);
+}
+
void ManagedEditor::OnEditorAssemblyLoaded(MAssembly* assembly)
{
ASSERT(!HasManagedInstance());
diff --git a/Source/Editor/Managed/ManagedEditor.h b/Source/Editor/Managed/ManagedEditor.h
index 5e0b612b5..df05e87bd 100644
--- a/Source/Editor/Managed/ManagedEditor.h
+++ b/Source/Editor/Managed/ManagedEditor.h
@@ -133,6 +133,11 @@ public:
/// True if exit engine, otherwise false.
bool OnAppExit();
+ ///
+ /// Requests play mode when the editor is in edit mode ( once ).
+ ///
+ void RequestStartPlayOnEditMode();
+
private:
void OnEditorAssemblyLoaded(MAssembly* assembly);
diff --git a/Source/Editor/Modules/SimulationModule.cs b/Source/Editor/Modules/SimulationModule.cs
index c1f2a3e7b..3faf5cd7e 100644
--- a/Source/Editor/Modules/SimulationModule.cs
+++ b/Source/Editor/Modules/SimulationModule.cs
@@ -203,6 +203,7 @@ namespace FlaxEditor.Modules
else if (!gameWin.IsSelected)
{
gameWin.SelectTab(false);
+ gameWin.RootWindow?.Window?.Focus();
FlaxEngine.GUI.RootControl.GameRoot.Focus();
}
}
diff --git a/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs b/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs
index 5e2792dc4..9dc0b1719 100644
--- a/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs
+++ b/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs
@@ -50,6 +50,7 @@ namespace FlaxEditor.SceneGraph.GUI
public ActorTreeNode()
: base(true)
{
+ ChildrenIndent = 16.0f;
}
internal virtual void LinkNode(ActorNode node)
@@ -567,121 +568,12 @@ namespace FlaxEditor.SceneGraph.GUI
{
for (int i = 0; i < _dragAssets.Objects.Count; i++)
{
- var assetItem = _dragAssets.Objects[i];
-
- if (assetItem.IsOfType())
- {
- // Create actor
- var model = FlaxEngine.Content.LoadAsync(assetItem.ID);
-
- var actor = new AnimatedModel
- {
- StaticFlags = Actor.StaticFlags,
- Name = assetItem.ShortName,
- SkinnedModel = model,
- Transform = Actor.Transform
- };
-
- // Spawn
- ActorNode.Root.Spawn(actor, Actor);
- }
- else if (assetItem.IsOfType())
- {
- // Create actor
- var model = FlaxEngine.Content.LoadAsync(assetItem.ID);
-
- var actor = new StaticModel
- {
- StaticFlags = Actor.StaticFlags,
- Name = assetItem.ShortName,
- Model = model,
- Transform = Actor.Transform
- };
-
- // Spawn
- ActorNode.Root.Spawn(actor, Actor);
- }
- else if (assetItem.IsOfType())
- {
- // Create actor
- var actor = new MeshCollider
- {
- StaticFlags = Actor.StaticFlags,
- Name = assetItem.ShortName,
- CollisionData = FlaxEngine.Content.LoadAsync(assetItem.ID),
- Transform = Actor.Transform
- };
-
- // Spawn
- ActorNode.Root.Spawn(actor, Actor);
- }
- else if (assetItem.IsOfType())
- {
- // Create actor
- var actor = new ParticleEffect
- {
- StaticFlags = Actor.StaticFlags,
- Name = assetItem.ShortName,
- ParticleSystem = FlaxEngine.Content.LoadAsync(assetItem.ID),
- Transform = Actor.Transform
- };
-
- // Spawn
- ActorNode.Root.Spawn(actor, Actor);
- }
- else if (assetItem.IsOfType())
- {
- // Create actor
- var actor = new SceneAnimationPlayer
- {
- StaticFlags = Actor.StaticFlags,
- Name = assetItem.ShortName,
- Animation = FlaxEngine.Content.LoadAsync(assetItem.ID),
- Transform = Actor.Transform
- };
-
- // Spawn
- ActorNode.Root.Spawn(actor, Actor);
- }
- else if (assetItem.IsOfType())
- {
- // Create actor
- var actor = new AudioSource
- {
- StaticFlags = Actor.StaticFlags,
- Name = assetItem.ShortName,
- Clip = FlaxEngine.Content.LoadAsync(assetItem.ID),
- Transform = Actor.Transform
- };
-
- // Spawn
- ActorNode.Root.Spawn(actor, Actor);
-
- break;
- }
- else if (assetItem.IsOfType())
- {
- // Create prefab instance
- var prefab = FlaxEngine.Content.LoadAsync(assetItem.ID);
- var actor = PrefabManager.SpawnPrefab(prefab, null);
- actor.StaticFlags = Actor.StaticFlags;
- actor.Name = assetItem.ShortName;
- actor.Transform = Actor.Transform;
-
- // Spawn
- ActorNode.Root.Spawn(actor, Actor);
- }
- else if (assetItem is VisualScriptItem visualScriptItem && new ScriptType(typeof(Actor)).IsAssignableFrom(visualScriptItem.ScriptType) && visualScriptItem.ScriptType.CanCreateInstance)
- {
- // Create actor
- var actor = (Actor)visualScriptItem.ScriptType.CreateInstance();
- actor.StaticFlags = Actor.StaticFlags;
- actor.Name = assetItem.ShortName;
- actor.Transform = Actor.Transform;
-
- // Spawn
- ActorNode.Root.Spawn(actor, Actor);
- }
+ var item = _dragAssets.Objects[i];
+ var actor = item.OnEditorDrop(this);
+ actor.StaticFlags = Actor.StaticFlags;
+ actor.Name = item.ShortName;
+ actor.Transform = Actor.Transform;
+ ActorNode.Root.Spawn(actor, Actor);
}
result = DragDropEffect.Move;
@@ -736,46 +628,12 @@ namespace FlaxEditor.SceneGraph.GUI
return actorNode.Actor != null && actorNode != ActorNode && actorNode.Find(Actor) == null;
}
- ///
- /// Validates the asset for drag and drop into one of the scene tree nodes.
- ///
- /// The item.
- /// True if can drag and drop it, otherwise false.
- public static bool ValidateDragAsset(AssetItem assetItem)
+ private bool ValidateDragAsset(AssetItem assetItem)
{
- if (assetItem.IsOfType())
- return true;
-
- if (assetItem.IsOfType())
- return true;
-
- if (assetItem.IsOfType())
- return true;
-
- if (assetItem.IsOfType())
- return true;
-
- if (assetItem.IsOfType())
- return true;
-
- if (assetItem.IsOfType())
- return true;
-
- if (assetItem.IsOfType())
- return true;
-
- if (assetItem is VisualScriptItem visualScriptItem && new ScriptType(typeof(Actor)).IsAssignableFrom(visualScriptItem.ScriptType) && visualScriptItem.ScriptType.CanCreateInstance)
- return true;
-
- return false;
+ return assetItem.OnEditorDrag(this);
}
- ///
- /// Validates the type of the actor for drag and drop into one of the scene tree nodes.
- ///
- /// Type of the actor.
- /// True if can drag and drop it, otherwise false.
- public static bool ValidateDragActorType(ScriptType actorType)
+ private static bool ValidateDragActorType(ScriptType actorType)
{
return true;
}
diff --git a/Source/Editor/Scripting/CodeEditors/VisualStudio/VisualStudioConnection.cpp b/Source/Editor/Scripting/CodeEditors/VisualStudio/VisualStudioConnection.cpp
index 54ba119f2..ffb4ff7b3 100644
--- a/Source/Editor/Scripting/CodeEditors/VisualStudio/VisualStudioConnection.cpp
+++ b/Source/Editor/Scripting/CodeEditors/VisualStudio/VisualStudioConnection.cpp
@@ -152,34 +152,10 @@ public:
namespace VisualStudio
{
- bool SameFile(HANDLE h1, HANDLE h2)
- {
- BY_HANDLE_FILE_INFORMATION bhfi1 = { 0 };
- BY_HANDLE_FILE_INFORMATION bhfi2 = { 0 };
-
- if (::GetFileInformationByHandle(h1, &bhfi1) && ::GetFileInformationByHandle(h2, &bhfi2))
- {
- return ((bhfi1.nFileIndexHigh == bhfi2.nFileIndexHigh) && (bhfi1.nFileIndexLow == bhfi2.nFileIndexLow) && (bhfi1.dwVolumeSerialNumber == bhfi2.dwVolumeSerialNumber));
- }
-
- return false;
- }
-
bool AreFilePathsEqual(const wchar_t* path1, const wchar_t* path2)
- {
- if (wcscmp(path1, path2) == 0)
- return true;
-
- HANDLE file1 = CreateFileW(path1, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
- HANDLE file2 = CreateFileW(path2, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
-
- bool result = SameFile(file1, file2);
-
- CloseHandle(file1);
- CloseHandle(file2);
-
- return result;
- }
+ {
+ return _wcsicmp(path1, path2) == 0;
+ }
class ConnectionInternal
{
diff --git a/Source/Editor/Scripting/CodeEditors/VisualStudio/VisualStudioEditor.cpp b/Source/Editor/Scripting/CodeEditors/VisualStudio/VisualStudioEditor.cpp
index dde2455a7..e8b221a5d 100644
--- a/Source/Editor/Scripting/CodeEditors/VisualStudio/VisualStudioEditor.cpp
+++ b/Source/Editor/Scripting/CodeEditors/VisualStudio/VisualStudioEditor.cpp
@@ -44,6 +44,7 @@ VisualStudioEditor::VisualStudioEditor(VisualStudioVersion version, const String
break;
}
_solutionPath = Globals::ProjectFolder / Editor::Project->Name + TEXT(".sln");
+ _solutionPath.Replace('/', '\\'); // Use Windows-style path separators
}
void VisualStudioEditor::FindEditors(Array* output)
@@ -145,7 +146,9 @@ void VisualStudioEditor::OpenFile(const String& path, int32 line)
// Open file
const VisualStudio::Connection connection(*_CLSID, *_solutionPath);
- const auto result = connection.OpenFile(*path, line);
+ String tmp = path;
+ tmp.Replace('/', '\\'); // Use Windows-style path separators
+ const auto result = connection.OpenFile(*tmp, line);
if (result.Failed())
{
LOG(Warning, "Cannot open file \'{0}\':{1}. {2}.", path, line, String(result.Message.c_str()));
diff --git a/Source/Editor/Scripting/ScriptType.cs b/Source/Editor/Scripting/ScriptType.cs
index 870d68eba..d5a064546 100644
--- a/Source/Editor/Scripting/ScriptType.cs
+++ b/Source/Editor/Scripting/ScriptType.cs
@@ -354,6 +354,10 @@ namespace FlaxEditor.Scripting
if (Type.Type == typeof(float))
sb.Append("Float");
+ else if (Type.Type == typeof(short))
+ sb.Append("Int16");
+ else if (Type.Type == typeof(ushort))
+ sb.Append("Uint16");
else if (Type.Type == typeof(int))
sb.Append("Int");
else if (Type.Type == typeof(uint))
@@ -389,6 +393,24 @@ namespace FlaxEditor.Scripting
else
sb.Append(asUint);
}
+ else if (DefaultValue is short asInt16)
+ {
+ if (asInt16 == short.MaxValue)
+ sb.Append("Int16.MaxValue");
+ else if (asInt16 == short.MinValue)
+ sb.Append("Int16.MinValue");
+ else
+ sb.Append(asInt16);
+ }
+ else if (DefaultValue is ushort asUint16)
+ {
+ if (asUint16 == ushort.MaxValue)
+ sb.Append("Uint16.MaxValue");
+ else if (asUint16 == ushort.MinValue)
+ sb.Append("Uint16.MinValue");
+ else
+ sb.Append(asUint16);
+ }
else if (DefaultValue is float asFloat)
{
if (asFloat == float.MaxValue)
@@ -703,6 +725,10 @@ namespace FlaxEditor.Scripting
return "Int";
if (_managed == typeof(uint))
return "Uint";
+ if (_managed == typeof(short))
+ return "Int16";
+ if (_managed == typeof(ushort))
+ return "Uint16";
if (_managed == typeof(bool))
return "Bool";
return _managed.Name;
diff --git a/Source/Editor/Utilities/VariantUtils.cs b/Source/Editor/Utilities/VariantUtils.cs
index eb044c9e9..d30cb26af 100644
--- a/Source/Editor/Utilities/VariantUtils.cs
+++ b/Source/Editor/Utilities/VariantUtils.cs
@@ -55,7 +55,10 @@ namespace FlaxEditor.Utilities
Int2,
Int3,
- Int4
+ Int4,
+
+ Int16,
+ Uint16,
}
internal static VariantType ToVariantType(this Type type)
@@ -67,6 +70,10 @@ namespace FlaxEditor.Utilities
variantType = VariantType.Void;
else if (type == typeof(bool))
variantType = VariantType.Bool;
+ else if (type == typeof(short))
+ variantType = VariantType.Int16;
+ else if (type == typeof(ushort))
+ variantType = VariantType.Uint16;
else if (type == typeof(int))
variantType = VariantType.Int;
else if (type == typeof(uint))
@@ -242,6 +249,8 @@ namespace FlaxEditor.Utilities
case VariantType.Null: return ScriptType.Null;
case VariantType.Void: return new ScriptType(typeof(void));
case VariantType.Bool: return new ScriptType(typeof(bool));
+ case VariantType.Int16: return new ScriptType(typeof(short));
+ case VariantType.Uint16: return new ScriptType(typeof(ushort));
case VariantType.Int: return new ScriptType(typeof(int));
case VariantType.Uint: return new ScriptType(typeof(uint));
case VariantType.Int64: return new ScriptType(typeof(long));
@@ -309,6 +318,8 @@ namespace FlaxEditor.Utilities
case VariantType.Null: return null;
case VariantType.Void: return typeof(void);
case VariantType.Bool: return typeof(bool);
+ case VariantType.Int16: return typeof(short);
+ case VariantType.Uint16: return typeof(ushort);
case VariantType.Int: return typeof(int);
case VariantType.Uint: return typeof(uint);
case VariantType.Int64: return typeof(long);
@@ -378,6 +389,8 @@ namespace FlaxEditor.Utilities
case VariantType.ManagedObject:
case VariantType.Void: return null;
case VariantType.Bool: return stream.ReadByte() != 0;
+ case VariantType.Int16: return stream.ReadInt16();
+ case VariantType.Uint16: return stream.ReadUInt16();
case VariantType.Int: return stream.ReadInt32();
case VariantType.Uint: return stream.ReadUInt32();
case VariantType.Int64: return stream.ReadInt64();
@@ -513,6 +526,12 @@ namespace FlaxEditor.Utilities
case VariantType.Bool:
stream.Write((byte)((bool)value ? 1 : 0));
break;
+ case VariantType.Int16:
+ stream.Write((short)value);
+ break;
+ case VariantType.Uint16:
+ stream.Write((ushort)value);
+ break;
case VariantType.Int:
stream.Write((int)value);
break;
@@ -687,6 +706,12 @@ namespace FlaxEditor.Utilities
case VariantType.Bool:
stream.WriteValue((bool)value);
break;
+ case VariantType.Int16:
+ stream.WriteValue((short)value);
+ break;
+ case VariantType.Uint16:
+ stream.WriteValue((ushort)value);
+ break;
case VariantType.Int:
stream.WriteValue((int)value);
break;
diff --git a/Source/Editor/Viewport/MainEditorGizmoViewport.cs b/Source/Editor/Viewport/MainEditorGizmoViewport.cs
index 0c895640d..ea63a598b 100644
--- a/Source/Editor/Viewport/MainEditorGizmoViewport.cs
+++ b/Source/Editor/Viewport/MainEditorGizmoViewport.cs
@@ -36,7 +36,7 @@ namespace FlaxEditor.Viewport
private readonly ViewportWidgetButton _rotateSnapping;
private readonly ViewportWidgetButton _scaleSnapping;
- private readonly DragAssets _dragAssets = new DragAssets(ValidateDragItem);
+ private readonly DragAssets _dragAssets;
private readonly DragActorType _dragActorType = new DragActorType(ValidateDragActorType);
private SelectionOutline _customSelectionOutline;
@@ -187,6 +187,7 @@ namespace FlaxEditor.Viewport
: base(Object.New(), editor.Undo)
{
_editor = editor;
+ _dragAssets = new DragAssets(ValidateDragItem);
// Prepare rendering task
Task.ActorsSource = ActorsSources.Scenes;
@@ -800,31 +801,19 @@ namespace FlaxEditor.Viewport
return result;
}
- private static bool ValidateDragItem(ContentItem contentItem)
+ private bool ValidateDragItem(ContentItem contentItem)
{
if (!Level.IsAnySceneLoaded)
return false;
if (contentItem is AssetItem assetItem)
{
- if (assetItem.IsOfType())
- return true;
- if (assetItem.IsOfType())
+ if (assetItem.OnEditorDrag(this))
return true;
if (assetItem.IsOfType())
return true;
- if (assetItem.IsOfType())
- return true;
- if (assetItem.IsOfType())
- return true;
- if (assetItem.IsOfType())
- return true;
- if (assetItem.IsOfType())
- return true;
if (assetItem.IsOfType())
return true;
- if (assetItem is VisualScriptItem visualScriptItem && new ScriptType(typeof(Actor)).IsAssignableFrom(visualScriptItem.ScriptType) && visualScriptItem.ScriptType.CanCreateInstance)
- return true;
}
return false;
@@ -891,119 +880,40 @@ namespace FlaxEditor.Viewport
private void Spawn(AssetItem item, SceneGraphNode hit, ref Vector2 location, ref Vector3 hitLocation)
{
- if (item is AssetItem assetItem)
+ if (item.IsOfType())
{
- if (assetItem.IsOfType())
+ if (hit is StaticModelNode staticModelNode)
{
- var asset = FlaxEngine.Content.LoadAsync(item.ID);
- var actor = new ParticleEffect
- {
- Name = item.ShortName,
- ParticleSystem = asset
- };
- Spawn(actor, ref hitLocation);
- return;
- }
- if (assetItem.IsOfType())
- {
- var asset = FlaxEngine.Content.LoadAsync(item.ID);
- var actor = new SceneAnimationPlayer
- {
- Name = item.ShortName,
- Animation = asset
- };
- Spawn(actor, ref hitLocation);
- return;
- }
- if (assetItem.IsOfType())
- {
- if (hit is StaticModelNode staticModelNode)
- {
- var staticModel = (StaticModel)staticModelNode.Actor;
- var ray = ConvertMouseToRay(ref location);
- if (staticModel.IntersectsEntry(ref ray, out _, out _, out var entryIndex))
- {
- var material = FlaxEngine.Content.LoadAsync(item.ID);
- using (new UndoBlock(Undo, staticModel, "Change material"))
- staticModel.SetMaterial(entryIndex, material);
- }
- }
- else if (hit is BoxBrushNode.SideLinkNode brushSurfaceNode)
+ var staticModel = (StaticModel)staticModelNode.Actor;
+ var ray = ConvertMouseToRay(ref location);
+ if (staticModel.IntersectsEntry(ref ray, out _, out _, out var entryIndex))
{
var material = FlaxEngine.Content.LoadAsync(item.ID);
- using (new UndoBlock(Undo, brushSurfaceNode.Brush, "Change material"))
- {
- var surface = brushSurfaceNode.Surface;
- surface.Material = material;
- brushSurfaceNode.Surface = surface;
- }
+ using (new UndoBlock(Undo, staticModel, "Change material"))
+ staticModel.SetMaterial(entryIndex, material);
}
- return;
}
- if (assetItem.IsOfType())
+ else if (hit is BoxBrushNode.SideLinkNode brushSurfaceNode)
{
- var model = FlaxEngine.Content.LoadAsync(item.ID);
- var actor = new AnimatedModel
+ var material = FlaxEngine.Content.LoadAsync(item.ID);
+ using (new UndoBlock(Undo, brushSurfaceNode.Brush, "Change material"))
{
- Name = item.ShortName,
- SkinnedModel = model
- };
- Spawn(actor, ref hitLocation);
- return;
- }
- if (assetItem.IsOfType())
- {
- var model = FlaxEngine.Content.LoadAsync(item.ID);
- var actor = new StaticModel
- {
- Name = item.ShortName,
- Model = model
- };
- Spawn(actor, ref hitLocation);
- return;
- }
- if (assetItem.IsOfType())
- {
- var collisionData = FlaxEngine.Content.LoadAsync(item.ID);
- var actor = new MeshCollider
- {
- Name = item.ShortName,
- CollisionData = collisionData
- };
- Spawn(actor, ref hitLocation);
- return;
- }
- if (assetItem.IsOfType())
- {
- var clip = FlaxEngine.Content.LoadAsync(item.ID);
- var actor = new AudioSource
- {
- Name = item.ShortName,
- Clip = clip
- };
- Spawn(actor, ref hitLocation);
- return;
- }
- if (assetItem.IsOfType())
- {
- var prefab = FlaxEngine.Content.LoadAsync(item.ID);
- var actor = PrefabManager.SpawnPrefab(prefab, null);
- actor.Name = item.ShortName;
- Spawn(actor, ref hitLocation);
- return;
- }
- if (assetItem.IsOfType())
- {
- Editor.Instance.Scene.OpenScene(item.ID, true);
- return;
- }
- if (assetItem is VisualScriptItem visualScriptItem && new ScriptType(typeof(Actor)).IsAssignableFrom(visualScriptItem.ScriptType) && visualScriptItem.ScriptType.CanCreateInstance)
- {
- var actor = (Actor)visualScriptItem.ScriptType.CreateInstance();
- actor.Name = item.ShortName;
- Spawn(actor, ref hitLocation);
- return;
+ var surface = brushSurfaceNode.Surface;
+ surface.Material = material;
+ brushSurfaceNode.Surface = surface;
+ }
}
+ return;
+ }
+ if (item.IsOfType())
+ {
+ Editor.Instance.Scene.OpenScene(item.ID, true);
+ return;
+ }
+ {
+ var actor = item.OnEditorDrop(this);
+ actor.Name = item.ShortName;
+ Spawn(actor, ref hitLocation);
}
}
diff --git a/Source/Editor/Viewport/PrefabWindowViewport.cs b/Source/Editor/Viewport/PrefabWindowViewport.cs
index 6483700b6..e189a8e62 100644
--- a/Source/Editor/Viewport/PrefabWindowViewport.cs
+++ b/Source/Editor/Viewport/PrefabWindowViewport.cs
@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
+using System.Security.Policy;
using FlaxEditor.Content;
using FlaxEditor.Gizmo;
using FlaxEditor.GUI.ContextMenu;
@@ -53,7 +54,7 @@ namespace FlaxEditor.Viewport
private readonly ViewportDebugDrawData _debugDrawData = new ViewportDebugDrawData(32);
private IntPtr _debugDrawContext;
private PrefabSpritesRenderer _spritesRenderer;
- private readonly DragAssets _dragAssets = new DragAssets(ValidateDragItem);
+ private readonly DragAssets _dragAssets;
private readonly DragActorType _dragActorType = new DragActorType(ValidateDragActorType);
private readonly DragHandlers _dragHandlers = new DragHandlers();
@@ -89,6 +90,7 @@ namespace FlaxEditor.Viewport
Undo = window.Undo;
ViewportCamera = new FPSCamera();
_debugDrawContext = DebugDraw.AllocateContext();
+ _dragAssets = new DragAssets(ValidateDragItem);
// Prepare rendering task
Task.ActorsSource = ActorsSources.CustomActors;
@@ -673,24 +675,14 @@ namespace FlaxEditor.Viewport
return _dragHandlers.OnDragEnter(data);
}
- private static bool ValidateDragItem(ContentItem contentItem)
+ private bool ValidateDragItem(ContentItem contentItem)
{
if (contentItem is AssetItem assetItem)
{
- if (assetItem.IsOfType())
+ if (assetItem.OnEditorDrag(this))
return true;
if (assetItem.IsOfType())
return true;
- if (assetItem.IsOfType())
- return true;
- if (assetItem.IsOfType())
- return true;
- if (assetItem.IsOfType())
- return true;
- if (assetItem.IsOfType())
- return true;
- if (assetItem is VisualScriptItem visualScriptItem && new ScriptType(typeof(Actor)).IsAssignableFrom(visualScriptItem.ScriptType) && visualScriptItem.ScriptType.CanCreateInstance)
- return true;
}
return false;
@@ -743,17 +735,6 @@ namespace FlaxEditor.Viewport
{
if (item is BinaryAssetItem binaryAssetItem)
{
- if (binaryAssetItem.Type == typeof(ParticleSystem))
- {
- var particleSystem = FlaxEngine.Content.LoadAsync(item.ID);
- var actor = new ParticleEffect
- {
- Name = item.ShortName,
- ParticleSystem = particleSystem
- };
- Spawn(actor, ref hitLocation);
- return;
- }
if (typeof(MaterialBase).IsAssignableFrom(binaryAssetItem.Type))
{
if (hit is StaticModelNode staticModelNode)
@@ -769,65 +750,11 @@ namespace FlaxEditor.Viewport
}
return;
}
- if (typeof(SkinnedModel).IsAssignableFrom(binaryAssetItem.Type))
- {
- var model = FlaxEngine.Content.LoadAsync(item.ID);
- var actor = new AnimatedModel
- {
- Name = item.ShortName,
- SkinnedModel = model
- };
- Spawn(actor, ref hitLocation);
- return;
- }
- if (typeof(Model).IsAssignableFrom(binaryAssetItem.Type))
- {
- var model = FlaxEngine.Content.LoadAsync(item.ID);
- var actor = new StaticModel
- {
- Name = item.ShortName,
- Model = model
- };
- Spawn(actor, ref hitLocation);
- return;
- }
- if (binaryAssetItem.IsOfType())
- {
- var collisionData = FlaxEngine.Content.LoadAsync(item.ID);
- var actor = new MeshCollider
- {
- Name = item.ShortName,
- CollisionData = collisionData
- };
- Spawn(actor, ref hitLocation);
- return;
- }
- if (typeof(AudioClip).IsAssignableFrom(binaryAssetItem.Type))
- {
- var clip = FlaxEngine.Content.LoadAsync(item.ID);
- var actor = new AudioSource
- {
- Name = item.ShortName,
- Clip = clip
- };
- Spawn(actor, ref hitLocation);
- return;
- }
- if (typeof(Prefab).IsAssignableFrom(binaryAssetItem.Type))
- {
- var prefab = FlaxEngine.Content.LoadAsync(item.ID);
- var actor = PrefabManager.SpawnPrefab(prefab, null);
- actor.Name = item.ShortName;
- Spawn(actor, ref hitLocation);
- return;
- }
}
- if (item is VisualScriptItem visualScriptItem && new ScriptType(typeof(Actor)).IsAssignableFrom(visualScriptItem.ScriptType) && visualScriptItem.ScriptType.CanCreateInstance)
{
- var actor = (Actor)visualScriptItem.ScriptType.CreateInstance();
+ var actor = item.OnEditorDrop(this);
actor.Name = item.ShortName;
Spawn(actor, ref hitLocation);
- return;
}
}
diff --git a/Source/Engine/Core/Types/Variant.cpp b/Source/Engine/Core/Types/Variant.cpp
index 97bcfc412..ac150d44d 100644
--- a/Source/Engine/Core/Types/Variant.cpp
+++ b/Source/Engine/Core/Types/Variant.cpp
@@ -160,6 +160,10 @@ const char* VariantType::GetTypeName() const
return "System.Void";
case Bool:
return "System.Boolean";
+ case Int16:
+ return "System.Int16";
+ case Uint16:
+ return "System.UInt16";
case Int:
return "System.Int32";
case Uint:
@@ -225,6 +229,12 @@ const char* VariantType::GetTypeName() const
case Bool:
result = TEXT("Bool");
break;
+ case Int16:
+ result = TEXT("Int16");
+ break;
+ case Uint16:
+ result = TEXT("Uint16");
+ break;
case Int:
result = TEXT("Int");
break;
@@ -417,6 +427,18 @@ Variant::Variant(bool v)
AsBool = v;
}
+Variant::Variant(int16 v)
+ : Type(VariantType::Int16)
+{
+ AsInt16 = v;
+}
+
+Variant::Variant(uint16 v)
+ : Type(VariantType::Uint16)
+{
+ AsUint16 = v;
+}
+
Variant::Variant(int32 v)
: Type(VariantType::Int)
{
@@ -896,6 +918,10 @@ bool Variant::operator==(const Variant& other) const
return true;
case VariantType::Bool:
return AsBool == other.AsBool;
+ case VariantType::Int16:
+ return AsInt16 == other.AsInt16;
+ case VariantType::Uint16:
+ return AsUint16 == other.AsUint16;
case VariantType::Int:
return AsInt == other.AsInt;
case VariantType::Uint:
@@ -1004,6 +1030,10 @@ bool Variant::operator<(const Variant& other) const
return true;
case VariantType::Bool:
return AsBool < other.AsBool;
+ case VariantType::Int16:
+ return AsInt16 < other.AsInt16;
+ case VariantType::Uint16:
+ return AsUint16 < other.AsUint16;
case VariantType::Int:
return AsInt < other.AsInt;
case VariantType::Uint:
@@ -1040,6 +1070,10 @@ Variant::operator bool() const
{
case VariantType::Bool:
return AsBool;
+ case VariantType::Int16:
+ return AsInt16 != 0;
+ case VariantType::Uint16:
+ return AsUint16 != 0;
case VariantType::Int:
return AsInt != 0;
case VariantType::Uint:
@@ -1075,6 +1109,10 @@ Variant::operator Char() const
{
case VariantType::Bool:
return AsBool ? 1 : 0;
+ case VariantType::Int16:
+ return (Char)AsInt16;
+ case VariantType::Uint16:
+ return (Char)AsUint16;
case VariantType::Int:
return (Char)AsInt;
case VariantType::Uint:
@@ -1101,6 +1139,10 @@ Variant::operator int8() const
{
case VariantType::Bool:
return AsBool ? 1 : 0;
+ case VariantType::Int16:
+ return (int8)AsInt16;
+ case VariantType::Uint16:
+ return (int8)AsUint16;
case VariantType::Int:
return (int8)AsInt;
case VariantType::Uint:
@@ -1127,6 +1169,10 @@ Variant::operator int16() const
{
case VariantType::Bool:
return AsBool ? 1 : 0;
+ case VariantType::Int16:
+ return AsInt16;
+ case VariantType::Uint16:
+ return (int16)AsUint16;
case VariantType::Int:
return (int16)AsInt;
case VariantType::Uint:
@@ -1153,6 +1199,10 @@ Variant::operator int32() const
{
case VariantType::Bool:
return AsBool ? 1 : 0;
+ case VariantType::Int16:
+ return (int32)AsInt16;
+ case VariantType::Uint16:
+ return (int32)AsUint16;
case VariantType::Int:
return AsInt;
case VariantType::Uint:
@@ -1179,6 +1229,10 @@ Variant::operator int64() const
{
case VariantType::Bool:
return AsBool ? 1 : 0;
+ case VariantType::Int16:
+ return (int64)AsInt16;
+ case VariantType::Uint16:
+ return (int64)AsUint16;
case VariantType::Int:
return (int64)AsInt;
case VariantType::Uint:
@@ -1205,6 +1259,10 @@ Variant::operator uint8() const
{
case VariantType::Bool:
return AsBool ? 1 : 0;
+ case VariantType::Int16:
+ return (uint8)AsInt16;
+ case VariantType::Uint16:
+ return (uint8)AsUint16;
case VariantType::Int:
return (uint8)AsInt;
case VariantType::Uint:
@@ -1231,6 +1289,10 @@ Variant::operator uint16() const
{
case VariantType::Bool:
return AsBool ? 1 : 0;
+ case VariantType::Int16:
+ return (uint16)AsInt16;
+ case VariantType::Uint16:
+ return AsUint16;
case VariantType::Int:
return (uint16)AsInt;
case VariantType::Uint:
@@ -1257,6 +1319,10 @@ Variant::operator uint32() const
{
case VariantType::Bool:
return AsBool ? 1 : 0;
+ case VariantType::Int16:
+ return (uint32)AsInt16;
+ case VariantType::Uint16:
+ return (uint32)AsUint16;
case VariantType::Int:
return (uint32)AsInt;
case VariantType::Uint:
@@ -1283,6 +1349,10 @@ Variant::operator uint64() const
{
case VariantType::Bool:
return AsBool ? 1 : 0;
+ case VariantType::Int16:
+ return (uint64)AsInt16;
+ case VariantType::Uint16:
+ return (uint64)AsUint16;
case VariantType::Int:
return (uint64)AsInt;
case VariantType::Uint:
@@ -1309,6 +1379,10 @@ Variant::operator float() const
{
case VariantType::Bool:
return AsBool ? 1.0f : 0.0f;
+ case VariantType::Int16:
+ return (float)AsInt16;
+ case VariantType::Uint16:
+ return (float)AsUint16;
case VariantType::Int:
return (float)AsInt;
case VariantType::Uint:
@@ -1333,6 +1407,10 @@ Variant::operator double() const
{
case VariantType::Bool:
return AsBool ? 1.0 : 0.0;
+ case VariantType::Int16:
+ return (double)AsInt16;
+ case VariantType::Uint16:
+ return (double)AsUint16;
case VariantType::Int:
return (double)AsInt;
case VariantType::Uint:
@@ -1423,6 +1501,10 @@ Variant::operator Vector2() const
{
case VariantType::Bool:
return Vector2(AsBool ? 1.0f : 0.0f);
+ case VariantType::Int16:
+ return Vector2((float)AsInt16);
+ case VariantType::Uint16:
+ return Vector2((float)AsUint16);
case VariantType::Int:
return Vector2((float)AsInt);
case VariantType::Uint:
@@ -1459,6 +1541,10 @@ Variant::operator Vector3() const
{
case VariantType::Bool:
return Vector3(AsBool ? 1.0f : 0.0f);
+ case VariantType::Int16:
+ return Vector3((float)AsInt16);
+ case VariantType::Uint16:
+ return Vector3((float)AsUint16);
case VariantType::Int:
return Vector3((float)AsInt);
case VariantType::Uint:
@@ -1495,6 +1581,10 @@ Variant::operator Vector4() const
{
case VariantType::Bool:
return Vector4(AsBool ? 1.0f : 0.0f);
+ case VariantType::Int16:
+ return Vector4((float)AsInt16);
+ case VariantType::Uint16:
+ return Vector4((float)AsUint16);
case VariantType::Int:
return Vector4((float)AsInt);
case VariantType::Uint:
@@ -1531,6 +1621,10 @@ Variant::operator Int2() const
{
case VariantType::Bool:
return Int2((int32)(AsBool ? 1.0f : 0.0f));
+ case VariantType::Int16:
+ return Int2((int32)AsInt16);
+ case VariantType::Uint16:
+ return Int2((int32)AsUint16);
case VariantType::Int:
return Int2((int32)AsInt);
case VariantType::Uint:
@@ -1573,6 +1667,10 @@ Variant::operator Int3() const
{
case VariantType::Bool:
return Int3((int32)(AsBool ? 1 : 0));
+ case VariantType::Int16:
+ return Int3((int32)AsInt16);
+ case VariantType::Uint16:
+ return Int3((int32)AsUint16);
case VariantType::Int:
return Int3((int32)AsInt);
case VariantType::Uint:
@@ -1615,6 +1713,10 @@ Variant::operator Int4() const
{
case VariantType::Bool:
return Int4((int32)(AsBool ? 1 : 0));
+ case VariantType::Int16:
+ return Int4(AsInt16);
+ case VariantType::Uint16:
+ return Int4((int32)AsUint16);
case VariantType::Int:
return Int4(AsInt);
case VariantType::Uint:
@@ -1657,6 +1759,10 @@ Variant::operator Color() const
{
case VariantType::Bool:
return Color(AsBool ? 1.0f : 0.0f);
+ case VariantType::Int16:
+ return Color((float)AsInt16);
+ case VariantType::Uint16:
+ return Color((float)AsUint16);
case VariantType::Int:
return Color((float)AsInt);
case VariantType::Uint:
@@ -2139,6 +2245,10 @@ String Variant::ToString() const
return TEXT("null");
case VariantType::Bool:
return AsBool ? TEXT("true") : TEXT("false");
+ case VariantType::Int16:
+ return StringUtils::ToString(AsInt16);
+ case VariantType::Uint16:
+ return StringUtils::ToString(AsUint16);
case VariantType::Int:
return StringUtils::ToString(AsInt);
case VariantType::Uint:
@@ -2207,6 +2317,8 @@ bool Variant::CanCast(const Variant& v, const VariantType& to)
case VariantType::Bool:
switch (to.Type)
{
+ case VariantType::Int16:
+ case VariantType::Uint16:
case VariantType::Int:
case VariantType::Uint:
case VariantType::Int64:
@@ -2221,10 +2333,50 @@ bool Variant::CanCast(const Variant& v, const VariantType& to)
default:
return false;
}
+ case VariantType::Int16:
+ switch (to.Type)
+ {
+ case VariantType::Bool:
+ case VariantType::Int:
+ case VariantType::Int64:
+ case VariantType::Uint16:
+ case VariantType::Uint:
+ case VariantType::Uint64:
+ case VariantType::Float:
+ case VariantType::Double:
+ case VariantType::Vector2:
+ case VariantType::Vector3:
+ case VariantType::Vector4:
+ case VariantType::Color:
+ return true;
+ default:
+ return false;
+ }
case VariantType::Int:
switch (to.Type)
{
case VariantType::Bool:
+ case VariantType::Int16:
+ case VariantType::Int64:
+ case VariantType::Uint16:
+ case VariantType::Uint:
+ case VariantType::Uint64:
+ case VariantType::Float:
+ case VariantType::Double:
+ case VariantType::Vector2:
+ case VariantType::Vector3:
+ case VariantType::Vector4:
+ case VariantType::Color:
+ return true;
+ default:
+ return false;
+ }
+ case VariantType::Uint16:
+ switch (to.Type)
+ {
+ case VariantType::Bool:
+ case VariantType::Int16:
+ case VariantType::Int:
case VariantType::Int64:
case VariantType::Uint:
case VariantType::Uint64:
@@ -2242,7 +2394,9 @@ bool Variant::CanCast(const Variant& v, const VariantType& to)
switch (to.Type)
{
case VariantType::Bool:
+ case VariantType::Uint16:
case VariantType::Uint64:
+ case VariantType::Int16:
case VariantType::Int:
case VariantType::Int64:
case VariantType::Float:
@@ -2259,7 +2413,9 @@ bool Variant::CanCast(const Variant& v, const VariantType& to)
switch (to.Type)
{
case VariantType::Bool:
+ case VariantType::Int16:
case VariantType::Int:
+ case VariantType::Uint16:
case VariantType::Uint:
case VariantType::Uint64:
case VariantType::Float:
@@ -2276,7 +2432,9 @@ bool Variant::CanCast(const Variant& v, const VariantType& to)
switch (to.Type)
{
case VariantType::Bool:
+ case VariantType::Uint16:
case VariantType::Uint:
+ case VariantType::Int16:
case VariantType::Int:
case VariantType::Int64:
case VariantType::Float:
@@ -2293,7 +2451,9 @@ bool Variant::CanCast(const Variant& v, const VariantType& to)
switch (to.Type)
{
case VariantType::Bool:
+ case VariantType::Int16:
case VariantType::Int:
+ case VariantType::Uint16:
case VariantType::Uint:
case VariantType::Int64:
case VariantType::Uint64:
@@ -2310,8 +2470,10 @@ bool Variant::CanCast(const Variant& v, const VariantType& to)
switch (to.Type)
{
case VariantType::Bool:
+ case VariantType::Int16:
case VariantType::Int:
case VariantType::Uint:
+ case VariantType::Uint16:
case VariantType::Int64:
case VariantType::Uint64:
case VariantType::Float:
@@ -2327,7 +2489,9 @@ bool Variant::CanCast(const Variant& v, const VariantType& to)
switch (to.Type)
{
case VariantType::Bool:
+ case VariantType::Uint16:
case VariantType::Uint:
+ case VariantType::Int16:
case VariantType::Int:
case VariantType::Int64:
case VariantType::Float:
@@ -2343,7 +2507,9 @@ bool Variant::CanCast(const Variant& v, const VariantType& to)
switch (to.Type)
{
case VariantType::Bool:
+ case VariantType::Uint16:
case VariantType::Uint:
+ case VariantType::Int16:
case VariantType::Int:
case VariantType::Int64:
case VariantType::Float:
@@ -2359,7 +2525,9 @@ bool Variant::CanCast(const Variant& v, const VariantType& to)
switch (to.Type)
{
case VariantType::Bool:
+ case VariantType::Uint16:
case VariantType::Uint:
+ case VariantType::Int16:
case VariantType::Int:
case VariantType::Int64:
case VariantType::Float:
@@ -2375,7 +2543,9 @@ bool Variant::CanCast(const Variant& v, const VariantType& to)
switch (to.Type)
{
case VariantType::Bool:
+ case VariantType::Uint16:
case VariantType::Uint:
+ case VariantType::Int16:
case VariantType::Int:
case VariantType::Int64:
case VariantType::Float:
@@ -2401,6 +2571,10 @@ Variant Variant::Cast(const Variant& v, const VariantType& to)
case VariantType::Bool:
switch (to.Type)
{
+ case VariantType::Int16: // No portable literal suffix for short ( Available in MSVC but Undocumented : i16 )
+ return Variant((int16)(v.AsBool ? 1 : 0));
+ case VariantType::Uint16: // No portable literal suffix for short ( Available in MSVC but Undocumented : ui16 )
+ return Variant((uint16)(v.AsBool ? 1 : 0));
case VariantType::Int:
return Variant(v.AsBool ? 1 : 0);
case VariantType::Uint:
@@ -2424,17 +2598,51 @@ Variant Variant::Cast(const Variant& v, const VariantType& to)
default: ;
}
break;
+ case VariantType::Int16:
+ switch (to.Type)
+ {
+ case VariantType::Bool:
+ return Variant(v.AsInt != 0);
+ case VariantType::Int:
+ return Variant((int32)v.AsInt16);
+ case VariantType::Int64:
+ return Variant((int64)v.AsInt16);
+ case VariantType::Uint16:
+ return Variant((uint16)v.AsInt16);
+ case VariantType::Uint:
+ return Variant((uint32)v.AsInt16);
+ case VariantType::Uint64:
+ return Variant((uint64)v.AsInt16);
+ case VariantType::Float:
+ return Variant((float)v.AsInt16);
+ case VariantType::Double:
+ return Variant((double)v.AsInt16);
+ case VariantType::Vector2:
+ return Variant(Vector2((float)v.AsInt16));
+ case VariantType::Vector3:
+ return Variant(Vector3((float)v.AsInt16));
+ case VariantType::Vector4:
+ return Variant(Vector4((float)v.AsInt16));
+ case VariantType::Color:
+ return Variant(Color((float)v.AsInt16));
+ default: ;
+ }
+ break;
case VariantType::Int:
switch (to.Type)
{
case VariantType::Bool:
return Variant(v.AsInt != 0);
+ case VariantType::Int16:
+ return Variant((int16)v.AsInt);
case VariantType::Int64:
- return Variant((int64)v.AsUint);
+ return Variant((int64)v.AsInt);
+ case VariantType::Uint16:
+ return Variant((uint16)v.AsInt);
case VariantType::Uint:
return Variant((uint32)v.AsInt);
case VariantType::Uint64:
- return Variant((uint64)v.AsUint);
+ return Variant((uint64)v.AsInt);
case VariantType::Float:
return Variant((float)v.AsInt);
case VariantType::Double:
@@ -2450,15 +2658,49 @@ Variant Variant::Cast(const Variant& v, const VariantType& to)
default: ;
}
break;
+ case VariantType::Uint16:
+ switch (to.Type)
+ {
+ case VariantType::Bool:
+ return Variant(v.AsUint16 != 0);
+ case VariantType::Int16:
+ return Variant((int16)v.AsUint16);
+ case VariantType::Int:
+ return Variant((int32)v.AsUint16);
+ case VariantType::Int64:
+ return Variant((int64)v.AsUint16);
+ case VariantType::Uint16:
+ return Variant((uint16)v.AsUint16);
+ case VariantType::Uint64:
+ return Variant((uint64)v.AsUint16);
+ case VariantType::Float:
+ return Variant((float)v.AsUint16);
+ case VariantType::Double:
+ return Variant((double)v.AsUint16);
+ case VariantType::Vector2:
+ return Variant(Vector2((float)v.AsUint16));
+ case VariantType::Vector3:
+ return Variant(Vector3((float)v.AsUint16));
+ case VariantType::Vector4:
+ return Variant(Vector4((float)v.AsUint16));
+ case VariantType::Color:
+ return Variant(Color((float)v.AsUint16));
+ default: ;
+ }
+ break;
case VariantType::Uint:
switch (to.Type)
{
case VariantType::Bool:
return Variant(v.AsUint != 0);
+ case VariantType::Int16:
+ return Variant((int16)v.AsUint);
case VariantType::Int:
return Variant((int32)v.AsUint);
case VariantType::Int64:
return Variant((int64)v.AsUint);
+ case VariantType::Uint16:
+ return Variant((uint16)v.AsUint);
case VariantType::Uint64:
return Variant((uint64)v.AsUint);
case VariantType::Float:
@@ -2481,8 +2723,12 @@ Variant Variant::Cast(const Variant& v, const VariantType& to)
{
case VariantType::Bool:
return Variant(v.AsInt64 != 0);
- case VariantType::Int64:
- return Variant((int64)v.AsUint);
+ case VariantType::Int16:
+ return Variant((int16)v.AsInt64);
+ case VariantType::Int:
+ return Variant((int32)v.AsInt64);
+ case VariantType::Uint16:
+ return Variant((uint16)v.AsInt64);
case VariantType::Uint:
return Variant((uint32)v.AsInt64);
case VariantType::Uint64:
@@ -2507,10 +2753,14 @@ Variant Variant::Cast(const Variant& v, const VariantType& to)
{
case VariantType::Bool:
return Variant(v.AsUint64 != 0);
+ case VariantType::Int16:
+ return Variant((int16)v.AsUint64);
case VariantType::Int:
return Variant((int32)v.AsUint64);
case VariantType::Int64:
return Variant((int64)v.AsUint64);
+ case VariantType::Uint16:
+ return Variant((uint16)v.AsUint16);
case VariantType::Uint:
return Variant((uint32)v.AsUint);
case VariantType::Float:
@@ -2533,8 +2783,12 @@ Variant Variant::Cast(const Variant& v, const VariantType& to)
{
case VariantType::Bool:
return Variant(Math::Abs(v.AsFloat) > ZeroTolerance);
+ case VariantType::Int16:
+ return Variant((int16)v.AsFloat);
case VariantType::Int:
return Variant((int32)v.AsFloat);
+ case VariantType::Uint16:
+ return Variant((uint16)v.AsFloat);
case VariantType::Uint:
return Variant((uint32)v.AsFloat);
case VariantType::Int64:
@@ -2559,8 +2813,12 @@ Variant Variant::Cast(const Variant& v, const VariantType& to)
{
case VariantType::Bool:
return Variant(Math::Abs(v.AsDouble) > ZeroTolerance);
+ case VariantType::Int16:
+ return Variant((int16)v.AsDouble);
case VariantType::Int:
return Variant((int32)v.AsDouble);
+ case VariantType::Uint16:
+ return Variant((uint16)v.AsDouble);
case VariantType::Uint:
return Variant((uint32)v.AsDouble);
case VariantType::Int64:
@@ -2585,8 +2843,12 @@ Variant Variant::Cast(const Variant& v, const VariantType& to)
{
case VariantType::Bool:
return Variant(Math::Abs(((Vector2*)v.AsData)->X) > ZeroTolerance);
+ case VariantType::Int16:
+ return Variant((int16)((Vector2*)v.AsData)->X);
case VariantType::Int:
return Variant((int32)((Vector2*)v.AsData)->X);
+ case VariantType::Uint16:
+ return Variant((uint16)((Vector2*)v.AsData)->X);
case VariantType::Uint:
return Variant((uint32)((Vector2*)v.AsData)->X);
case VariantType::Int64:
@@ -2611,8 +2873,12 @@ Variant Variant::Cast(const Variant& v, const VariantType& to)
{
case VariantType::Bool:
return Variant(Math::Abs(((Vector3*)v.AsData)->X) > ZeroTolerance);
+ case VariantType::Int16:
+ return Variant((int16)((Vector3*)v.AsData)->X);
case VariantType::Int:
return Variant((int32)((Vector3*)v.AsData)->X);
+ case VariantType::Uint16:
+ return Variant((uint16)((Vector3*)v.AsData)->X);
case VariantType::Uint:
return Variant((uint32)((Vector3*)v.AsData)->X);
case VariantType::Int64:
@@ -2637,8 +2903,12 @@ Variant Variant::Cast(const Variant& v, const VariantType& to)
{
case VariantType::Bool:
return Variant(Math::Abs(((Vector4*)v.AsData)->X) > ZeroTolerance);
+ case VariantType::Int16:
+ return Variant((int16)((Vector4*)v.AsData)->X);
case VariantType::Int:
return Variant((int32)((Vector4*)v.AsData)->X);
+ case VariantType::Uint16:
+ return Variant((uint16)((Vector4*)v.AsData)->X);
case VariantType::Uint:
return Variant((uint32)((Vector4*)v.AsData)->X);
case VariantType::Int64:
@@ -2663,8 +2933,12 @@ Variant Variant::Cast(const Variant& v, const VariantType& to)
{
case VariantType::Bool:
return Variant(Math::Abs(((Color*)v.AsData)->R) > ZeroTolerance);
+ case VariantType::Int16:
+ return Variant((int16)((Color*)v.AsData)->R);
case VariantType::Int:
return Variant((int32)((Color*)v.AsData)->R);
+ case VariantType::Uint16:
+ return Variant((uint16)((Color*)v.AsData)->R);
case VariantType::Uint:
return Variant((uint32)((Color*)v.AsData)->R);
case VariantType::Int64:
@@ -2696,6 +2970,8 @@ bool Variant::NearEqual(const Variant& a, const Variant& b, float epsilon)
return false;
switch (a.Type.Type)
{
+ case VariantType::Int16:
+ return Math::Abs(a.AsInt16 - b.AsInt16) <= (int32)epsilon;
case VariantType::Int:
return Math::Abs(a.AsInt - b.AsInt) <= (int32)epsilon;
case VariantType::Int64:
@@ -2737,8 +3013,12 @@ Variant Variant::Lerp(const Variant& a, const Variant& b, float alpha)
{
case VariantType::Bool:
return alpha < 0.5f ? a : b;
+ case VariantType::Int16:
+ return Math::Lerp(a.AsInt16, b.AsInt16, alpha);
case VariantType::Int:
return Math::Lerp(a.AsInt, b.AsInt, alpha);
+ case VariantType::Uint16:
+ return Math::Lerp(a.AsUint16, b.AsUint16, alpha);
case VariantType::Uint:
return Math::Lerp(a.AsUint, b.AsUint, alpha);
case VariantType::Int64:
@@ -2844,8 +3124,12 @@ uint32 GetHash(const Variant& key)
{
case VariantType::Bool:
return GetHash(key.AsBool);
+ case VariantType::Int16:
+ return GetHash(key.AsInt16);
case VariantType::Int:
return GetHash(key.AsInt);
+ case VariantType::Uint16:
+ return GetHash(key.AsUint16);
case VariantType::Uint:
return GetHash(key.AsUint);
case VariantType::Int64:
diff --git a/Source/Engine/Core/Types/Variant.h b/Source/Engine/Core/Types/Variant.h
index ac9af0e79..6ab7a7a67 100644
--- a/Source/Engine/Core/Types/Variant.h
+++ b/Source/Engine/Core/Types/Variant.h
@@ -58,6 +58,9 @@ API_STRUCT(InBuild) struct FLAXENGINE_API VariantType
Int3,
Int4,
+ Int16,
+ Uint16,
+
MAX
};
@@ -135,6 +138,8 @@ API_STRUCT(InBuild) struct FLAXENGINE_API Variant
union
{
bool AsBool;
+ int16 AsInt16;
+ uint16 AsUint16;
int32 AsInt;
uint32 AsUint;
int64 AsInt64;
@@ -184,6 +189,8 @@ public:
Variant(Variant&& other) noexcept;
Variant(bool v);
+ Variant(int16 v);
+ Variant(uint16 v);
Variant(int32 v);
Variant(uint32 v);
Variant(int64 v);
diff --git a/Source/Engine/Engine/CommandLine.cpp b/Source/Engine/Engine/CommandLine.cpp
index d6c03b070..9f5078c64 100644
--- a/Source/Engine/Engine/CommandLine.cpp
+++ b/Source/Engine/Engine/CommandLine.cpp
@@ -102,6 +102,23 @@ bool CommandLine::Parse(const Char* cmdLine)
*(end - len) = 0; \
end -= len; \
}
+
+#define PARSE_ARG_OPT_SWITCH(text, field) \
+ pos = (Char*)StringUtils::FindIgnoreCase(buffer.Get(), TEXT(text)); \
+ if (pos) \
+ { \
+ len = ARRAY_COUNT(text) - 1; \
+ if (ParseArg(pos + len, argStart, argEnd)) \
+ Options.field = String::Empty; \
+ else \
+ { \
+ Options.field = String(argStart, static_cast(argEnd - argStart)); \
+ len = static_cast((argEnd - pos) + 1); \
+ Platform::MemoryCopy(pos, pos + len, (end - pos - len) * 2); \
+ *(end - len) = 0; \
+ end -= len; \
+ } \
+ }
PARSE_BOOL_SWITCH("-windowed ", Windowed);
PARSE_BOOL_SWITCH("-fullscreen ", Fullscreen);
@@ -137,6 +154,7 @@ bool CommandLine::Parse(const Char* cmdLine)
PARSE_ARG_SWITCH("-build ", Build);
PARSE_BOOL_SWITCH("-skipcompile ", SkipCompile);
PARSE_BOOL_SWITCH("-shaderdebug ", ShaderDebug);
+ PARSE_ARG_OPT_SWITCH("-play ", Play);
#endif
diff --git a/Source/Engine/Engine/CommandLine.h b/Source/Engine/Engine/CommandLine.h
index 62b38ca99..d9d3547d3 100644
--- a/Source/Engine/Engine/CommandLine.h
+++ b/Source/Engine/Engine/CommandLine.h
@@ -164,6 +164,11 @@ public:
///
Nullable ShaderDebug;
+ ///
+ /// -play !guid! ( Scene to play, can be empty to use default )
+ ///
+ Nullable Play;
+
#endif
};
diff --git a/Source/Engine/Graphics/Models/Mesh.cpp b/Source/Engine/Graphics/Models/Mesh.cpp
index dddbd6a3e..35b5fe5fb 100644
--- a/Source/Engine/Graphics/Models/Mesh.cpp
+++ b/Source/Engine/Graphics/Models/Mesh.cpp
@@ -363,7 +363,8 @@ void Mesh::GetDrawCallGeometry(DrawCall& drawCall) const
void Mesh::Render(GPUContext* context) const
{
- ASSERT(IsInitialized());
+ if (!IsInitialized())
+ return;
context->BindVB(ToSpan((GPUBuffer**)_vertexBuffers, 3));
context->BindIB(_indexBuffer);
@@ -372,7 +373,7 @@ void Mesh::Render(GPUContext* context) const
void Mesh::Draw(const RenderContext& renderContext, MaterialBase* material, const Matrix& world, StaticFlags flags, bool receiveDecals, DrawPass drawModes, float perInstanceRandom) const
{
- if (!material || !material->IsSurface())
+ if (!material || !material->IsSurface() || !IsInitialized())
return;
// Submit draw call
diff --git a/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.ParticleModules.cpp b/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.ParticleModules.cpp
index ae25e01e0..4d8e02a97 100644
--- a/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.ParticleModules.cpp
+++ b/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.ParticleModules.cpp
@@ -3,6 +3,12 @@
#include "ParticleEmitterGraph.CPU.h"
#include "Engine/Core/Random.h"
+// ReSharper disable CppCStyleCast
+// ReSharper disable CppClangTidyClangDiagnosticCastAlign
+// ReSharper disable CppDefaultCaseNotHandledInSwitchStatement
+// ReSharper disable CppClangTidyCppcoreguidelinesMacroUsage
+// ReSharper disable CppClangTidyClangDiagnosticOldStyleCast
+
#define RAND Random::Rand()
#define RAND2 Vector2(RAND, RAND)
#define RAND3 Vector3(RAND, RAND, RAND)
@@ -62,7 +68,7 @@ namespace
float scale = 1.0f;
for (int32 i = 0; i < octaves; i++)
{
- const float curWeight = Math::Pow(1.0f - ((float)i / octaves), Math::Lerp(2.0f, 0.2f, roughness));
+ const float curWeight = Math::Pow(1.0f - ((float)i / (float)octaves), Math::Lerp(2.0f, 0.2f, roughness));
noise += Noise3D(position * scale) * curWeight;
weight += curWeight;
@@ -156,7 +162,7 @@ int32 ParticleEmitterGraphCPUExecutor::ProcessSpawnModule(int32 index)
// Calculate actual spawn amount
spawnCount = Math::Max(spawnCount, 0.0f);
const int32 result = Math::FloorToInt(spawnCount);
- spawnCount -= result;
+ spawnCount -= (float)result;
data.SpawnCounter = spawnCount;
return result;
@@ -475,7 +481,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
auto& velocity = _data->Buffer->Layout->Attributes[node->Attributes[0]];
auto& mass = _data->Buffer->Layout->Attributes[node->Attributes[1]];
- byte* spriteSizePtr = useSpriteSize ? start + _data->Buffer->Layout->Attributes[node->Attributes[2]].Offset : 0;
+ byte* spriteSizePtr = useSpriteSize ? start + _data->Buffer->Layout->Attributes[node->Attributes[2]].Offset : nullptr;
byte* velocityPtr = start + velocity.Offset;
byte* massPtr = start + mass.Offset;
diff --git a/Source/Engine/Physics/Actors/WheeledVehicle.h b/Source/Engine/Physics/Actors/WheeledVehicle.h
index bb947d68d..1941038bf 100644
--- a/Source/Engine/Physics/Actors/WheeledVehicle.h
+++ b/Source/Engine/Physics/Actors/WheeledVehicle.h
@@ -156,7 +156,7 @@ public:
// Left wheel of the rear axle.
RearLeft,
// Right wheel of the rear axle.
- ReadRight,
+ RearRight,
// Non-drivable wheel.
NoDrive,
};
diff --git a/Source/Engine/Platform/Windows/WindowsPlatform.cpp b/Source/Engine/Platform/Windows/WindowsPlatform.cpp
index 00a5c0d0f..2086cd8dc 100644
--- a/Source/Engine/Platform/Windows/WindowsPlatform.cpp
+++ b/Source/Engine/Platform/Windows/WindowsPlatform.cpp
@@ -4,6 +4,7 @@
#include "Engine/Platform/Platform.h"
#include "Engine/Platform/Window.h"
+#include "Engine/Platform/FileSystem.h"
#include "Engine/Platform/CreateWindowSettings.h"
#include "Engine/Platform/WindowsManager.h"
#include "Engine/Platform/MemoryStats.h"
@@ -1118,6 +1119,19 @@ void* WindowsPlatform::LoadLibrary(const Char* filename)
{
ASSERT(filename);
+ // Add folder to search path to load dependency libraries
+ StringView folder = StringUtils::GetDirectoryName(filename);
+ if (folder.HasChars() && FileSystem::IsRelative(folder))
+ folder = StringView::Empty;
+ if (folder.HasChars())
+ {
+ Char& end = ((Char*)folder.Get())[folder.Length()];
+ const Char c = end;
+ end = 0;
+ SetDllDirectoryW(*folder);
+ end = c;
+ }
+
// Avoiding windows dialog boxes if missing
const DWORD errorMode = SEM_NOOPENFILEERRORBOX;
DWORD prevErrorMode = 0;
@@ -1134,12 +1148,15 @@ void* WindowsPlatform::LoadLibrary(const Char* filename)
{
SetThreadErrorMode(prevErrorMode, nullptr);
}
+ if (folder.HasChars())
+ {
+ SetDllDirectoryW(nullptr);
+ }
#if CRASH_LOG_ENABLE
// Refresh modules info during next stack trace collecting to have valid debug symbols information
SymLocker.Lock();
- const auto folder = StringUtils::GetDirectoryName(filename);
- if (!SymbolsPath.Contains(folder))
+ if (folder.HasChars() && !SymbolsPath.Contains(folder))
{
SymbolsPath.Add(folder);
OnSymbolsPathModified();
diff --git a/Source/Engine/Render2D/FontManager.cpp b/Source/Engine/Render2D/FontManager.cpp
index 13b46991f..a8e16f715 100644
--- a/Source/Engine/Render2D/FontManager.cpp
+++ b/Source/Engine/Render2D/FontManager.cpp
@@ -287,6 +287,8 @@ bool FontManager::AddNewEntry(Font* font, Char c, FontCharacterEntry& entry)
void FontManager::Invalidate(FontCharacterEntry& entry)
{
+ if (entry.TextureIndex == MAX_uint8)
+ return;
auto atlas = Atlases[entry.TextureIndex];
const uint32 padding = atlas->GetPaddingAmount();
const uint32 slotX = static_cast(entry.UV.X - padding);
diff --git a/Source/Engine/Scripting/ManagedCLR/MUtils.cpp b/Source/Engine/Scripting/ManagedCLR/MUtils.cpp
index 8c9326337..a43220f08 100644
--- a/Source/Engine/Scripting/ManagedCLR/MUtils.cpp
+++ b/Source/Engine/Scripting/ManagedCLR/MUtils.cpp
@@ -154,13 +154,13 @@ VariantType MUtils::UnboxVariantType(MonoType* monoType)
if (klass == mono_get_boolean_class() || monoType->type == MONO_TYPE_BOOLEAN)
return VariantType(VariantType::Bool);
if (klass == mono_get_byte_class() || monoType->type == MONO_TYPE_U1)
- return VariantType(VariantType::Int);
+ return VariantType(VariantType::Int16);
if (klass == mono_get_sbyte_class() || monoType->type == MONO_TYPE_I1)
- return VariantType(VariantType::Int);
+ return VariantType(VariantType::Int16);
if (klass == mono_get_int16_class() || monoType->type == MONO_TYPE_I2)
- return VariantType(VariantType::Int);
+ return VariantType(VariantType::Int16);
if (klass == mono_get_uint16_class() || monoType->type == MONO_TYPE_U2)
- return VariantType(VariantType::Uint);
+ return VariantType(VariantType::Uint16);
if (klass == mono_get_int32_class() || monoType->type == MONO_TYPE_I4)
return VariantType(VariantType::Int);
if (klass == mono_get_uint32_class() || monoType->type == MONO_TYPE_U4)
@@ -266,13 +266,13 @@ Variant MUtils::UnboxVariant(MonoObject* value)
if (klass == mono_get_boolean_class())
return *static_cast(mono_object_unbox(value));
if (klass == mono_get_byte_class())
- return (int32)*static_cast(mono_object_unbox(value));
+ return (int16)*static_cast(mono_object_unbox(value));
if (klass == mono_get_sbyte_class())
- return (int32)*static_cast(mono_object_unbox(value));
+ return (int16)*static_cast(mono_object_unbox(value));
if (klass == mono_get_int16_class())
- return (int32)*static_cast(mono_object_unbox(value));
+ return *static_cast(mono_object_unbox(value));
if (klass == mono_get_uint16_class())
- return (uint32)*static_cast(mono_object_unbox(value));
+ return *static_cast(mono_object_unbox(value));
if (klass == mono_get_int32_class())
return *static_cast(mono_object_unbox(value));
if (klass == mono_get_uint32_class())
@@ -365,6 +365,10 @@ MonoObject* MUtils::BoxVariant(const Variant& value)
return nullptr;
case VariantType::Bool:
return mono_value_box(mono_domain_get(), mono_get_boolean_class(), (void*)&value.AsBool);
+ case VariantType::Int16:
+ return mono_value_box(mono_domain_get(), mono_get_int16_class(), (void*)&value.AsInt16);
+ case VariantType::Uint16:
+ return mono_value_box(mono_domain_get(), mono_get_uint16_class(), (void*)&value.AsUint16);
case VariantType::Int:
return mono_value_box(mono_domain_get(), mono_get_int32_class(), (void*)&value.AsInt);
case VariantType::Uint:
@@ -534,6 +538,10 @@ MonoClass* MUtils::GetClass(const VariantType& value)
return mono_get_void_class();
case VariantType::Bool:
return mono_get_boolean_class();
+ case VariantType::Int16:
+ return mono_get_int16_class();
+ case VariantType::Uint16:
+ return mono_get_uint16_class();
case VariantType::Int:
return mono_get_int32_class();
case VariantType::Uint:
@@ -600,6 +608,10 @@ MonoClass* MUtils::GetClass(const Variant& value)
return mono_get_void_class();
case VariantType::Bool:
return mono_get_boolean_class();
+ case VariantType::Int16:
+ return mono_get_int16_class();
+ case VariantType::Uint16:
+ return mono_get_uint16_class();
case VariantType::Int:
return mono_get_int32_class();
case VariantType::Uint:
@@ -700,12 +712,18 @@ void* MUtils::VariantToManagedArgPtr(Variant& value, const MType& type, bool& fa
case MONO_TYPE_CHAR:
case MONO_TYPE_I1:
case MONO_TYPE_I2:
+ if (value.Type.Type != VariantType::Int16)
+ value = (int16)value;
+ return &value.AsInt16;
case MONO_TYPE_I4:
if (value.Type.Type != VariantType::Int)
value = (int32)value;
return &value.AsInt;
case MONO_TYPE_U1:
case MONO_TYPE_U2:
+ if (value.Type.Type != VariantType::Uint16)
+ value = (uint16)value;
+ return &value.AsUint16;
case MONO_TYPE_U4:
if (value.Type.Type != VariantType::Uint)
value = (uint32)value;
diff --git a/Source/Engine/Serialization/JsonConverters.cs b/Source/Engine/Serialization/JsonConverters.cs
index 2ebf16a79..149bdc241 100644
--- a/Source/Engine/Serialization/JsonConverters.cs
+++ b/Source/Engine/Serialization/JsonConverters.cs
@@ -123,6 +123,13 @@ namespace FlaxEngine.Json
writer.WriteStartObject();
{
+#if FLAX_EDITOR
+ if ((serializer.TypeNameHandling & TypeNameHandling.Objects) == TypeNameHandling.Objects)
+ {
+ writer.WritePropertyName("$type");
+ writer.WriteValue("FlaxEngine.Margin, FlaxEngine.CSharp");
+ }
+#endif
writer.WritePropertyName("Left");
writer.WriteValue(valueMargin.Left);
writer.WritePropertyName("Right");
diff --git a/Source/Engine/Serialization/Stream.cpp b/Source/Engine/Serialization/Stream.cpp
index 269d49562..21d10f987 100644
--- a/Source/Engine/Serialization/Stream.cpp
+++ b/Source/Engine/Serialization/Stream.cpp
@@ -274,6 +274,12 @@ void ReadStream::ReadVariant(Variant* data)
case VariantType::Bool:
data->AsBool = ReadBool();
break;
+ case VariantType::Int16:
+ ReadInt16(&data->AsInt16);
+ break;
+ case VariantType::Uint16:
+ ReadUint16(&data->AsUint16);
+ break;
case VariantType::Int:
ReadInt32(&data->AsInt);
break;
@@ -573,6 +579,12 @@ void WriteStream::WriteVariant(const Variant& data)
case VariantType::Bool:
WriteBool(data.AsBool);
break;
+ case VariantType::Int16:
+ WriteInt16(data.AsInt16);
+ break;
+ case VariantType::Uint16:
+ WriteUint16(data.AsUint16);
+ break;
case VariantType::Int:
WriteInt32(data.AsInt);
break;
diff --git a/Source/Engine/UI/GUI/Brushes/GPUTextureBrush.cs b/Source/Engine/UI/GUI/Brushes/GPUTextureBrush.cs
index f91e3dfe3..77ad80758 100644
--- a/Source/Engine/UI/GUI/Brushes/GPUTextureBrush.cs
+++ b/Source/Engine/UI/GUI/Brushes/GPUTextureBrush.cs
@@ -14,6 +14,12 @@ namespace FlaxEngine.GUI
[HideInEditor]
public GPUTexture Texture;
+ ///
+ /// The texture sampling filter mode.
+ ///
+ [ExpandGroups, Tooltip("The texture sampling filter mode.")]
+ public BrushFilter Filter = BrushFilter.Linear;
+
///
/// Initializes a new instance of the class.
///
@@ -36,7 +42,10 @@ namespace FlaxEngine.GUI
///
public void Draw(Rectangle rect, Color color)
{
- Render2D.DrawTexture(Texture, rect, color);
+ if (Filter == BrushFilter.Point)
+ Render2D.DrawTexturePoint(Texture, rect, color);
+ else
+ Render2D.DrawTexture(Texture, rect, color);
}
}
}
diff --git a/Source/Engine/UI/GUI/Brushes/IBrush.cs b/Source/Engine/UI/GUI/Brushes/IBrush.cs
index ec5ba420a..5e4df2694 100644
--- a/Source/Engine/UI/GUI/Brushes/IBrush.cs
+++ b/Source/Engine/UI/GUI/Brushes/IBrush.cs
@@ -2,6 +2,24 @@
namespace FlaxEngine.GUI
{
+ ///
+ /// Texture brush sampling modes.
+ ///
+ public enum BrushFilter
+ {
+ ///
+ /// The point sampling without blending.
+ ///
+ [Tooltip("The point sampling without blending.")]
+ Point = 0,
+
+ ///
+ /// The linear color sampling.
+ ///
+ [Tooltip("The linear color sampling.")]
+ Linear = 1,
+ };
+
///
/// Interface that unifies input source textures, sprites, render targets, and any other brushes to be used in a more generic way.
///
diff --git a/Source/Engine/UI/GUI/Brushes/SpriteBrush.cs b/Source/Engine/UI/GUI/Brushes/SpriteBrush.cs
index 9867e1f25..05c0bb2e2 100644
--- a/Source/Engine/UI/GUI/Brushes/SpriteBrush.cs
+++ b/Source/Engine/UI/GUI/Brushes/SpriteBrush.cs
@@ -11,9 +11,15 @@ namespace FlaxEngine.GUI
///
/// The sprite.
///
- [ExpandGroups]
+ [ExpandGroups, EditorOrder(0), Tooltip("The sprite.")]
public SpriteHandle Sprite;
+ ///
+ /// The texture sampling filter mode.
+ ///
+ [ExpandGroups, EditorOrder(1), Tooltip("The texture sampling filter mode.")]
+ public BrushFilter Filter = BrushFilter.Linear;
+
///
/// Initializes a new instance of the class.
///
@@ -36,7 +42,10 @@ namespace FlaxEngine.GUI
///
public void Draw(Rectangle rect, Color color)
{
- Render2D.DrawSprite(Sprite, rect, color);
+ if (Filter == BrushFilter.Point)
+ Render2D.DrawSpritePoint(Sprite, rect, color);
+ else
+ Render2D.DrawSprite(Sprite, rect, color);
}
}
}
diff --git a/Source/Engine/UI/GUI/Brushes/TextureBrush.cs b/Source/Engine/UI/GUI/Brushes/TextureBrush.cs
index 118128c71..1f772e0a6 100644
--- a/Source/Engine/UI/GUI/Brushes/TextureBrush.cs
+++ b/Source/Engine/UI/GUI/Brushes/TextureBrush.cs
@@ -1,5 +1,7 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
+using System;
+
namespace FlaxEngine.GUI
{
///
@@ -11,9 +13,15 @@ namespace FlaxEngine.GUI
///
/// The texture.
///
- [ExpandGroups, Tooltip("The texture asset.")]
+ [ExpandGroups, EditorOrder(0), Tooltip("The texture asset.")]
public Texture Texture;
+ ///
+ /// The texture sampling filter mode.
+ ///
+ [ExpandGroups, EditorOrder(1), Tooltip("The texture sampling filter mode.")]
+ public BrushFilter Filter = BrushFilter.Linear;
+
///
/// Initializes a new instance of the class.
///
@@ -36,7 +44,10 @@ namespace FlaxEngine.GUI
///
public void Draw(Rectangle rect, Color color)
{
- Render2D.DrawTexture(Texture, rect, color);
+ if (Filter == BrushFilter.Point)
+ Render2D.DrawTexturePoint(Texture?.Texture, rect, color);
+ else
+ Render2D.DrawTexture(Texture, rect, color);
}
}
}
diff --git a/Source/Tools/Flax.Build/Bindings/ApiTypeInfo.cs b/Source/Tools/Flax.Build/Bindings/ApiTypeInfo.cs
index 3e2ad1b31..6667aab9f 100644
--- a/Source/Tools/Flax.Build/Bindings/ApiTypeInfo.cs
+++ b/Source/Tools/Flax.Build/Bindings/ApiTypeInfo.cs
@@ -71,6 +71,13 @@ namespace Flax.Build.Bindings
}
}
+ public void EnsureInited(Builder.BuildData buildData)
+ {
+ if (IsInited)
+ return;
+ Init(buildData);
+ }
+
public virtual void Init(Builder.BuildData buildData)
{
IsInited = true;
diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Api.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Api.cs
index 27c902a5c..ded954e5a 100644
--- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Api.cs
+++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Api.cs
@@ -261,7 +261,7 @@ namespace Flax.Build.Bindings
{
if (typeInfo == null)
return null;
- var result = FindApiTypeInfoInner(typeInfo, caller);
+ var result = FindApiTypeInfoInner(buildData, typeInfo, caller);
if (result != null)
return result;
if (buildData.TypeCache.TryGetValue(typeInfo, out result))
@@ -274,7 +274,7 @@ namespace Flax.Build.Bindings
// Find across all loaded modules for this build
foreach (var e in buildData.ModulesInfo)
{
- result = FindApiTypeInfoInner(typeInfo, e.Value);
+ result = FindApiTypeInfoInner(buildData, typeInfo, e.Value);
if (result != null)
{
buildData.TypeCache.Add(typeInfo, result);
@@ -291,7 +291,7 @@ namespace Flax.Build.Bindings
{
if (result == null)
return null;
- result = FindApiTypeInfoInner(new TypeInfo { Type = nesting[i], }, result);
+ result = FindApiTypeInfoInner(buildData, new TypeInfo { Type = nesting[i], }, result);
}
return result;
}
@@ -301,14 +301,17 @@ namespace Flax.Build.Bindings
return null;
}
- private static ApiTypeInfo FindApiTypeInfoInner(TypeInfo typeInfo, ApiTypeInfo parent)
+ private static ApiTypeInfo FindApiTypeInfoInner(BuildData buildData, TypeInfo typeInfo, ApiTypeInfo parent)
{
foreach (var child in parent.Children)
{
if (child.Name == typeInfo.Type)
+ {
+ child.EnsureInited(buildData);
return child;
+ }
- var result = FindApiTypeInfoInner(typeInfo, child);
+ var result = FindApiTypeInfoInner(buildData, typeInfo, child);
if (result != null)
return result;
}
diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs
index 26fa55231..37e5dda23 100644
--- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs
+++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs
@@ -14,7 +14,7 @@ namespace Flax.Build.Bindings
private static readonly HashSet CSharpUsedNamespaces = new HashSet();
private static readonly List CSharpUsedNamespacesSorted = new List();
- private static readonly Dictionary CSharpNativeToManagedBasicTypes = new Dictionary()
+ internal static readonly Dictionary CSharpNativeToManagedBasicTypes = new Dictionary()
{
// Language types
{ "int8", "sbyte" },
@@ -32,7 +32,7 @@ namespace Flax.Build.Bindings
{ "double", "double" },
};
- private static readonly Dictionary CSharpNativeToManagedDefault = new Dictionary()
+ internal static readonly Dictionary CSharpNativeToManagedDefault = new Dictionary()
{
// Engine types
{ "String", "string" },
@@ -201,6 +201,8 @@ namespace Flax.Build.Bindings
var apiType = FindApiTypeInfo(buildData, typeInfo, caller);
if (apiType != null)
{
+ CSharpUsedNamespaces.Add(apiType.Namespace);
+
if (apiType.IsScriptingObject)
return typeInfo.Type.Replace("::", ".");
@@ -527,7 +529,7 @@ namespace Flax.Build.Bindings
contents.Append("abstract ");
contents.Append("unsafe partial class ").Append(classInfo.Name);
if (classInfo.BaseType != null && !classInfo.IsBaseTypeHidden)
- contents.Append(" : ").Append(GenerateCSharpNativeToManaged(buildData, classInfo.BaseType, classInfo));
+ contents.Append(" : ").Append(GenerateCSharpNativeToManaged(buildData, new TypeInfo { Type = classInfo.BaseType.Name }, classInfo));
contents.AppendLine();
contents.Append(indent + "{");
indent += " ";
@@ -861,7 +863,7 @@ namespace Flax.Build.Bindings
contents.Append("private ");
contents.Append("unsafe partial struct ").Append(structureInfo.Name);
if (structureInfo.BaseType != null && structureInfo.IsPod)
- contents.Append(" : ").Append(GenerateCSharpNativeToManaged(buildData, structureInfo.BaseType, structureInfo));
+ contents.Append(" : ").Append(GenerateCSharpNativeToManaged(buildData, new TypeInfo { Type = structureInfo.BaseType.Name }, structureInfo));
contents.AppendLine();
contents.Append(indent + "{");
indent += " ";
@@ -1048,30 +1050,6 @@ namespace Flax.Build.Bindings
return true;
}
- private static void GenerateCSharpCollectNamespaces(BuildData buildData, ApiTypeInfo apiType, HashSet usedNamespaces)
- {
- if (apiType is ClassInfo classInfo)
- {
- foreach (var field in classInfo.Fields)
- {
- var fieldInfo = FindApiTypeInfo(buildData, field.Type, classInfo);
- if (fieldInfo != null && !string.IsNullOrWhiteSpace(fieldInfo.Namespace) && fieldInfo.Namespace != apiType.Namespace)
- usedNamespaces.Add(fieldInfo.Namespace);
- }
- }
- else if (apiType is StructureInfo structureInfo)
- {
- foreach (var field in structureInfo.Fields)
- {
- var fieldInfo = FindApiTypeInfo(buildData, field.Type, structureInfo);
- if (fieldInfo != null && !string.IsNullOrWhiteSpace(fieldInfo.Namespace) && fieldInfo.Namespace != apiType.Namespace)
- usedNamespaces.Add(fieldInfo.Namespace);
- }
- }
- foreach (var child in apiType.Children)
- GenerateCSharpCollectNamespaces(buildData, child, usedNamespaces);
- }
-
private static void GenerateCSharp(BuildData buildData, ModuleInfo moduleInfo, ref BindingsResult bindings)
{
var contents = new StringBuilder();
@@ -1084,29 +1062,17 @@ namespace Flax.Build.Bindings
contents.Append("true").AppendLine();
contents.AppendLine("// This code was auto-generated. Do not modify it.");
contents.AppendLine();
+ var headerPos = contents.Length;
- // Using declarations
CSharpUsedNamespaces.Clear();
+ CSharpUsedNamespaces.Add(null);
+ CSharpUsedNamespaces.Add(string.Empty);
CSharpUsedNamespaces.Add("System");
CSharpUsedNamespaces.Add("System.ComponentModel");
CSharpUsedNamespaces.Add("System.Globalization");
CSharpUsedNamespaces.Add("System.Runtime.CompilerServices");
CSharpUsedNamespaces.Add("System.Runtime.InteropServices");
CSharpUsedNamespaces.Add("FlaxEngine");
- foreach (var e in moduleInfo.Children)
- {
- foreach (var apiTypeInfo in e.Children)
- {
- GenerateCSharpCollectNamespaces(buildData, apiTypeInfo, CSharpUsedNamespaces);
- }
- }
- CSharpUsedNamespacesSorted.Clear();
- CSharpUsedNamespacesSorted.AddRange(CSharpUsedNamespaces);
- CSharpUsedNamespacesSorted.Sort();
- foreach (var e in CSharpUsedNamespacesSorted)
- contents.AppendLine($"using {e};");
- // TODO: custom using declarations support
- // TODO: generate using declarations based on references modules (eg. using FlaxEngine, using Plugin1 in game API)
// Process all API types from the file
var useBindings = false;
@@ -1121,7 +1087,21 @@ namespace Flax.Build.Bindings
if (!useBindings)
return;
+ {
+ var header = new StringBuilder();
+
+ // Using declarations
+ CSharpUsedNamespacesSorted.Clear();
+ CSharpUsedNamespacesSorted.AddRange(CSharpUsedNamespaces);
+ CSharpUsedNamespacesSorted.Sort();
+ for (var i = 2; i < CSharpUsedNamespacesSorted.Count; i++)
+ header.AppendLine($"using {CSharpUsedNamespacesSorted[i]};");
+
+ contents.Insert(headerPos, header.ToString());
+ }
+
// Save generated file
+ contents.AppendLine();
contents.AppendLine("#endif");
Utilities.WriteFileIfChanged(bindings.GeneratedCSharpFilePath, contents.ToString());
}
diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs
index 8fc7d18f2..0bb1f4cc7 100644
--- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs
+++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs
@@ -19,7 +19,7 @@ namespace Flax.Build.Bindings
partial class BindingsGenerator
{
private static readonly Dictionary TypeCache = new Dictionary();
- private const int CacheVersion = 7;
+ private const int CacheVersion = 8;
internal static void Write(BinaryWriter writer, string e)
{
diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs
index 78fd3df73..a2fffddd4 100644
--- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs
+++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs
@@ -1095,7 +1095,7 @@ namespace Flax.Build.Bindings
var baseType = classInfo?.BaseType ?? structureInfo?.BaseType;
if (classInfo != null && classInfo.IsBaseTypeHidden)
baseType = null;
- if (baseType != null && (baseType.Type == "PersistentScriptingObject" || baseType.Type == "ScriptingObject"))
+ if (baseType != null && (baseType.Name == "PersistentScriptingObject" || baseType.Name == "ScriptingObject"))
baseType = null;
CppAutoSerializeFields.Clear();
CppAutoSerializeProperties.Clear();
@@ -1105,7 +1105,7 @@ namespace Flax.Build.Bindings
contents.Append($"void {typeNameNative}::Serialize(SerializeStream& stream, const void* otherObj)").AppendLine();
contents.Append('{').AppendLine();
if (baseType != null)
- contents.Append($" {baseType}::Serialize(stream, otherObj);").AppendLine();
+ contents.Append($" {baseType.FullNameNative}::Serialize(stream, otherObj);").AppendLine();
contents.Append($" SERIALIZE_GET_OTHER_OBJ({typeNameNative});").AppendLine();
if (classInfo != null)
@@ -1161,7 +1161,7 @@ namespace Flax.Build.Bindings
contents.Append($"void {typeNameNative}::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)").AppendLine();
contents.Append('{').AppendLine();
if (baseType != null)
- contents.Append($" {baseType}::Deserialize(stream, modifier);").AppendLine();
+ contents.Append($" {baseType.FullNameNative}::Deserialize(stream, modifier);").AppendLine();
foreach (var fieldInfo in CppAutoSerializeFields)
{
@@ -1554,7 +1554,7 @@ namespace Flax.Build.Bindings
else
contents.Append($"(ScriptingType::SpawnHandler)&{classTypeNameNative}::Spawn, ");
if (classInfo.BaseType != null && useScripting)
- contents.Append($"&{classInfo.BaseType}::TypeInitializer, ");
+ contents.Append($"&{classInfo.BaseType.FullNameNative}::TypeInitializer, ");
else
contents.Append("nullptr, ");
contents.Append(setupScriptVTable);
@@ -1566,7 +1566,7 @@ namespace Flax.Build.Bindings
else
contents.Append($"&{classTypeNameInternal}Internal::Ctor, &{classTypeNameInternal}Internal::Dtor, ");
if (classInfo.BaseType != null)
- contents.Append($"&{classInfo.BaseType}::TypeInitializer");
+ contents.Append($"&{classInfo.BaseType.FullNameNative}::TypeInitializer");
else
contents.Append("nullptr");
}
diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs
index 67e90efa9..8ed4a1634 100644
--- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs
+++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs
@@ -416,38 +416,38 @@ namespace Flax.Build.Bindings
token = accessToken;
break;
}
-
- var baseTypeInfo = new TypeInfo
+ var inheritType = new TypeInfo
{
Type = token.Value,
};
- if (token.Value.Length > 2 && token.Value[0] == 'I' && char.IsUpper(token.Value[1]))
- {
- // Interface
- if (desc.InterfaceNames == null)
- desc.InterfaceNames = new List();
- desc.InterfaceNames.Add(baseTypeInfo);
- token = context.Tokenizer.NextToken();
- continue;
- }
-
- if (desc.BaseType != null)
- {
- // Allow for multiple base classes, just the first one needs to be a valid base type
- break;
- throw new Exception($"Invalid '{desc.Name}' inheritance (only single base class is allowed for scripting types, excluding interfaces).");
- }
- desc.BaseType = baseTypeInfo;
+ if (desc.Inheritance == null)
+ desc.Inheritance = new List();
+ desc.Inheritance.Add(inheritType);
token = context.Tokenizer.NextToken();
if (token.Type == TokenType.LeftCurlyBrace)
{
break;
}
+ if (token.Type == TokenType.Colon)
+ {
+ token = context.Tokenizer.ExpectToken(TokenType.Colon);
+ token = context.Tokenizer.NextToken();
+ inheritType.Type = token.Value;
+ token = context.Tokenizer.NextToken();
+ continue;
+ }
+ if (token.Type == TokenType.DoubleColon)
+ {
+ token = context.Tokenizer.NextToken();
+ inheritType.Type += token.Value;
+ token = context.Tokenizer.NextToken();
+ continue;
+ }
if (token.Type == TokenType.LeftAngleBracket)
{
var genericType = context.Tokenizer.ExpectToken(TokenType.Identifier);
token = context.Tokenizer.ExpectToken(TokenType.RightAngleBracket);
- desc.BaseType.GenericArgs = new List
+ inheritType.GenericArgs = new List
{
new TypeInfo
{
@@ -456,9 +456,9 @@ namespace Flax.Build.Bindings
};
// TODO: find better way to resolve this (custom base type attribute?)
- if (desc.BaseType.Type == "ShaderAssetTypeBase")
+ if (inheritType.Type == "ShaderAssetTypeBase")
{
- desc.BaseType = desc.BaseType.GenericArgs[0];
+ desc.Inheritance[desc.Inheritance.Count - 1] = inheritType.GenericArgs[0];
}
token = context.Tokenizer.NextToken();
diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.cs
index f8d26314f..fa219477a 100644
--- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.cs
+++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.cs
@@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Flax.Build.NativeCpp;
@@ -109,13 +108,6 @@ namespace Flax.Build.Bindings
if (LoadCache(ref moduleInfo, moduleOptions, headerFiles))
{
buildData.ModulesInfo[module] = moduleInfo;
-
- // Initialize API
- using (new ProfileEventScope("Init"))
- {
- moduleInfo.Init(buildData);
- }
-
return moduleInfo;
}
}
@@ -164,12 +156,6 @@ namespace Flax.Build.Bindings
}
}
- // Initialize API
- using (new ProfileEventScope("Init"))
- {
- moduleInfo.Init(buildData);
- }
-
return moduleInfo;
}
@@ -533,23 +519,10 @@ namespace Flax.Build.Bindings
if (moduleInfo.IsFromCache)
return;
- // Process parsed API
- using (new ProfileEventScope("Process"))
+ // Initialize parsed API
+ using (new ProfileEventScope("Init"))
{
- foreach (var child in moduleInfo.Children)
- {
- try
- {
- foreach (var apiTypeInfo in child.Children)
- ProcessAndValidate(buildData, apiTypeInfo);
- }
- catch (Exception)
- {
- if (child is FileInfo fileInfo)
- Log.Error($"Failed to validate '{fileInfo.Name}' file to generate bindings.");
- throw;
- }
- }
+ moduleInfo.Init(buildData);
}
// Generate bindings for scripting
@@ -583,122 +556,5 @@ namespace Flax.Build.Bindings
}
}
}
-
- private static void ProcessAndValidate(BuildData buildData, ApiTypeInfo apiTypeInfo)
- {
- if (apiTypeInfo is ClassInfo classInfo)
- ProcessAndValidate(buildData, classInfo);
- else if (apiTypeInfo is StructureInfo structureInfo)
- ProcessAndValidate(buildData, structureInfo);
-
- foreach (var child in apiTypeInfo.Children)
- ProcessAndValidate(buildData, child);
- }
-
- private static void ProcessAndValidate(BuildData buildData, ClassInfo classInfo)
- {
- if (classInfo.UniqueFunctionNames == null)
- classInfo.UniqueFunctionNames = new HashSet();
-
- foreach (var fieldInfo in classInfo.Fields)
- {
- if (fieldInfo.Access == AccessLevel.Private)
- continue;
-
- fieldInfo.Getter = new FunctionInfo
- {
- Name = "Get" + fieldInfo.Name,
- Comment = fieldInfo.Comment,
- IsStatic = fieldInfo.IsStatic,
- Access = fieldInfo.Access,
- Attributes = fieldInfo.Attributes,
- ReturnType = fieldInfo.Type,
- Parameters = new List(),
- IsVirtual = false,
- IsConst = true,
- Glue = new FunctionInfo.GlueInfo()
- };
- ProcessAndValidate(classInfo, fieldInfo.Getter);
- fieldInfo.Getter.Name = fieldInfo.Name;
-
- if (!fieldInfo.IsReadOnly)
- {
- fieldInfo.Setter = new FunctionInfo
- {
- Name = "Set" + fieldInfo.Name,
- Comment = fieldInfo.Comment,
- IsStatic = fieldInfo.IsStatic,
- Access = fieldInfo.Access,
- Attributes = fieldInfo.Attributes,
- ReturnType = new TypeInfo
- {
- Type = "void",
- },
- Parameters = new List
- {
- new FunctionInfo.ParameterInfo
- {
- Name = "value",
- Type = fieldInfo.Type,
- },
- },
- IsVirtual = false,
- IsConst = true,
- Glue = new FunctionInfo.GlueInfo()
- };
- ProcessAndValidate(classInfo, fieldInfo.Setter);
- fieldInfo.Setter.Name = fieldInfo.Name;
- }
- }
-
- foreach (var propertyInfo in classInfo.Properties)
- {
- if (propertyInfo.Getter != null)
- ProcessAndValidate(classInfo, propertyInfo.Getter);
- if (propertyInfo.Setter != null)
- ProcessAndValidate(classInfo, propertyInfo.Setter);
- }
-
- foreach (var functionInfo in classInfo.Functions)
- ProcessAndValidate(classInfo, functionInfo);
- }
-
- private static void ProcessAndValidate(BuildData buildData, StructureInfo structureInfo)
- {
- foreach (var fieldInfo in structureInfo.Fields)
- {
- if (fieldInfo.Type.IsBitField)
- throw new NotImplementedException($"TODO: support bit-fields in structure fields (found field {fieldInfo} in structure {structureInfo.Name})");
-
- // Pointers are fine
- if (fieldInfo.Type.IsPtr)
- continue;
-
- // In-build types
- if (CSharpNativeToManagedBasicTypes.ContainsKey(fieldInfo.Type.Type))
- continue;
- if (CSharpNativeToManagedDefault.ContainsKey(fieldInfo.Type.Type))
- continue;
-
- // Find API type info for this field type
- var apiType = FindApiTypeInfo(buildData, fieldInfo.Type, structureInfo);
- if (apiType != null)
- continue;
-
- throw new Exception($"Unknown field type '{fieldInfo.Type} {fieldInfo.Name}' in structure '{structureInfo.Name}'.");
- }
- }
-
- private static void ProcessAndValidate(ClassInfo classInfo, FunctionInfo functionInfo)
- {
- // Ensure that methods have unique names for bindings
- if (classInfo.UniqueFunctionNames == null)
- classInfo.UniqueFunctionNames = new HashSet();
- int idx = 1;
- functionInfo.UniqueName = functionInfo.Name;
- while (classInfo.UniqueFunctionNames.Contains(functionInfo.UniqueName))
- functionInfo.UniqueName = functionInfo.Name + idx++;
- classInfo.UniqueFunctionNames.Add(functionInfo.UniqueName);
- }
}
}
diff --git a/Source/Tools/Flax.Build/Bindings/ClassInfo.cs b/Source/Tools/Flax.Build/Bindings/ClassInfo.cs
index c68ff1a59..ff0bb077b 100644
--- a/Source/Tools/Flax.Build/Bindings/ClassInfo.cs
+++ b/Source/Tools/Flax.Build/Bindings/ClassInfo.cs
@@ -57,22 +57,87 @@ namespace Flax.Build.Bindings
_isScriptingObject = true;
else if (BaseType == null)
_isScriptingObject = false;
- else if (InBuildScriptingObjectTypes.Contains(BaseType.Type))
+ else if (InBuildScriptingObjectTypes.Contains(BaseType.Name))
_isScriptingObject = true;
else
+ _isScriptingObject = BaseType != null && BaseType.IsScriptingObject;
+
+ if (UniqueFunctionNames == null)
+ UniqueFunctionNames = new HashSet();
+
+ foreach (var fieldInfo in Fields)
{
- var baseApiTypeInfo = BindingsGenerator.FindApiTypeInfo(buildData, BaseType, this);
- if (baseApiTypeInfo != null)
+ if (fieldInfo.Access == AccessLevel.Private)
+ continue;
+
+ fieldInfo.Getter = new FunctionInfo
{
- if (!baseApiTypeInfo.IsInited)
- baseApiTypeInfo.Init(buildData);
- _isScriptingObject = baseApiTypeInfo.IsScriptingObject;
- }
- else
+ Name = "Get" + fieldInfo.Name,
+ Comment = fieldInfo.Comment,
+ IsStatic = fieldInfo.IsStatic,
+ Access = fieldInfo.Access,
+ Attributes = fieldInfo.Attributes,
+ ReturnType = fieldInfo.Type,
+ Parameters = new List(),
+ IsVirtual = false,
+ IsConst = true,
+ Glue = new FunctionInfo.GlueInfo()
+ };
+ ProcessAndValidate(fieldInfo.Getter);
+ fieldInfo.Getter.Name = fieldInfo.Name;
+
+ if (!fieldInfo.IsReadOnly)
{
- _isScriptingObject = false;
+ fieldInfo.Setter = new FunctionInfo
+ {
+ Name = "Set" + fieldInfo.Name,
+ Comment = fieldInfo.Comment,
+ IsStatic = fieldInfo.IsStatic,
+ Access = fieldInfo.Access,
+ Attributes = fieldInfo.Attributes,
+ ReturnType = new TypeInfo
+ {
+ Type = "void",
+ },
+ Parameters = new List
+ {
+ new FunctionInfo.ParameterInfo
+ {
+ Name = "value",
+ Type = fieldInfo.Type,
+ },
+ },
+ IsVirtual = false,
+ IsConst = true,
+ Glue = new FunctionInfo.GlueInfo()
+ };
+ ProcessAndValidate(fieldInfo.Setter);
+ fieldInfo.Setter.Name = fieldInfo.Name;
}
}
+
+ foreach (var propertyInfo in Properties)
+ {
+ if (propertyInfo.Getter != null)
+ ProcessAndValidate(propertyInfo.Getter);
+ if (propertyInfo.Setter != null)
+ ProcessAndValidate(propertyInfo.Setter);
+ }
+
+ foreach (var functionInfo in Functions)
+ ProcessAndValidate(functionInfo);
+ }
+
+ private void ProcessAndValidate(FunctionInfo functionInfo)
+ {
+ // Ensure that methods have unique names for bindings
+ if (UniqueFunctionNames == null)
+ UniqueFunctionNames = new HashSet();
+ int idx = 1;
+ functionInfo.UniqueName = functionInfo.Name;
+ while (UniqueFunctionNames.Contains(functionInfo.UniqueName))
+ functionInfo.UniqueName = functionInfo.Name + idx++;
+ UniqueFunctionNames.Add(functionInfo.UniqueName);
}
public override void Write(BinaryWriter writer)
@@ -113,7 +178,7 @@ namespace Flax.Build.Bindings
{
if (_scriptVTableSize == -1)
{
- if (BindingsGenerator.FindApiTypeInfo(buildData, BaseType, this) is ClassInfo baseApiTypeInfo)
+ if (BaseType is ClassInfo baseApiTypeInfo)
{
_scriptVTableOffset = baseApiTypeInfo.GetScriptVTableSize(buildData, out _);
}
diff --git a/Source/Tools/Flax.Build/Bindings/ClassStructInfo.cs b/Source/Tools/Flax.Build/Bindings/ClassStructInfo.cs
index 2f0dad003..ca1bb9257 100644
--- a/Source/Tools/Flax.Build/Bindings/ClassStructInfo.cs
+++ b/Source/Tools/Flax.Build/Bindings/ClassStructInfo.cs
@@ -1,5 +1,6 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
+using System;
using System.Collections.Generic;
using System.IO;
@@ -12,29 +13,37 @@ namespace Flax.Build.Bindings
{
public AccessLevel Access;
public AccessLevel BaseTypeInheritance;
- public TypeInfo BaseType;
- public List Interfaces; // Optional
- public List InterfaceNames; // Optional
+ public ClassStructInfo BaseType;
+ public List Interfaces;
+ public List Inheritance; // Data from parsing, used to interfaces and base type construct in Init
public override void Init(Builder.BuildData buildData)
{
base.Init(buildData);
- if (Interfaces == null && InterfaceNames != null && InterfaceNames.Count != 0)
+ if (BaseType == null && Interfaces == null && Inheritance != null)
{
- Interfaces = new List();
- for (var i = 0; i < InterfaceNames.Count; i++)
+ // Extract base class and interfaces from inheritance info
+ for (int i = 0; i < Inheritance.Count; i++)
{
- var interfaceName = InterfaceNames[i];
- var apiTypeInfo = BindingsGenerator.FindApiTypeInfo(buildData, interfaceName, this);
+ var apiTypeInfo = BindingsGenerator.FindApiTypeInfo(buildData, Inheritance[i], Parent);
if (apiTypeInfo is InterfaceInfo interfaceInfo)
{
+ if (Interfaces == null)
+ Interfaces = new List();
Interfaces.Add(interfaceInfo);
}
+ else if (apiTypeInfo is ClassStructInfo otherInfo)
+ {
+ if (otherInfo == this)
+ throw new Exception($"Type '{Name}' inherits from itself.");
+ if (BaseType != null)
+ throw new Exception($"Invalid '{Name}' inheritance (only single base class is allowed for scripting types, excluding interfaces).");
+ BaseType = otherInfo;
+ }
}
- if (Interfaces.Count == 0)
- Interfaces = null;
}
+ BaseType?.EnsureInited(buildData);
}
public override void Write(BinaryWriter writer)
@@ -42,7 +51,7 @@ namespace Flax.Build.Bindings
writer.Write((byte)Access);
writer.Write((byte)BaseTypeInheritance);
BindingsGenerator.Write(writer, BaseType);
- BindingsGenerator.Write(writer, InterfaceNames);
+ BindingsGenerator.Write(writer, Inheritance);
base.Write(writer);
}
@@ -52,7 +61,7 @@ namespace Flax.Build.Bindings
Access = (AccessLevel)reader.ReadByte();
BaseTypeInheritance = (AccessLevel)reader.ReadByte();
BaseType = BindingsGenerator.Read(reader, BaseType);
- InterfaceNames = BindingsGenerator.Read(reader, InterfaceNames);
+ Inheritance = BindingsGenerator.Read(reader, Inheritance);
base.Read(reader);
}
diff --git a/Source/Tools/Flax.Build/Bindings/FileInfo.cs b/Source/Tools/Flax.Build/Bindings/FileInfo.cs
index 6c4b4dcfe..7a38c8d87 100644
--- a/Source/Tools/Flax.Build/Bindings/FileInfo.cs
+++ b/Source/Tools/Flax.Build/Bindings/FileInfo.cs
@@ -17,6 +17,19 @@ namespace Flax.Build.Bindings
base.AddChild(apiTypeInfo);
}
+ public override void Init(Builder.BuildData buildData)
+ {
+ try
+ {
+ base.Init(buildData);
+ }
+ catch (Exception)
+ {
+ Log.Error($"Failed to init '{Name}' file scripting API.");
+ throw;
+ }
+ }
+
public int CompareTo(FileInfo other)
{
return Name.CompareTo(other.Name);
diff --git a/Source/Tools/Flax.Build/Bindings/StructureInfo.cs b/Source/Tools/Flax.Build/Bindings/StructureInfo.cs
index 5b664cc09..7e6888d91 100644
--- a/Source/Tools/Flax.Build/Bindings/StructureInfo.cs
+++ b/Source/Tools/Flax.Build/Bindings/StructureInfo.cs
@@ -26,14 +26,14 @@ namespace Flax.Build.Bindings
{
base.Init(buildData);
- if (ForceNoPod || (InterfaceNames != null && InterfaceNames.Count != 0))
+ if (ForceNoPod || (Interfaces != null && Interfaces.Count != 0))
{
_isPod = false;
return;
}
// Structure is POD (plain old data) only if all of it's fields are (and has no base type ro base type is also POD)
- _isPod = BaseType == null || (BindingsGenerator.FindApiTypeInfo(buildData, BaseType, Parent)?.IsPod ?? false);
+ _isPod = BaseType == null || (BaseType?.IsPod ?? false);
for (int i = 0; _isPod && i < Fields.Count; i++)
{
var field = Fields[i];
@@ -42,6 +42,29 @@ namespace Flax.Build.Bindings
_isPod = false;
}
}
+
+ foreach (var fieldInfo in Fields)
+ {
+ if (fieldInfo.Type.IsBitField)
+ throw new NotImplementedException($"TODO: support bit-fields in structure fields (found field {fieldInfo} in structure {Name})");
+
+ // Pointers are fine
+ if (fieldInfo.Type.IsPtr)
+ continue;
+
+ // In-build types
+ if (BindingsGenerator.CSharpNativeToManagedBasicTypes.ContainsKey(fieldInfo.Type.Type))
+ continue;
+ if (BindingsGenerator.CSharpNativeToManagedDefault.ContainsKey(fieldInfo.Type.Type))
+ continue;
+
+ // Find API type info for this field type
+ var apiType = BindingsGenerator.FindApiTypeInfo(buildData, fieldInfo.Type, this);
+ if (apiType != null)
+ continue;
+
+ throw new Exception($"Unknown field type '{fieldInfo.Type} {fieldInfo.Name}' in structure '{Name}'.");
+ }
}
public override void Write(BinaryWriter writer)
diff --git a/Source/Tools/Flax.Build/Bindings/TypeInfo.cs b/Source/Tools/Flax.Build/Bindings/TypeInfo.cs
index 443b0687a..9268e5998 100644
--- a/Source/Tools/Flax.Build/Bindings/TypeInfo.cs
+++ b/Source/Tools/Flax.Build/Bindings/TypeInfo.cs
@@ -36,8 +36,7 @@ namespace Flax.Build.Bindings
var apiType = BindingsGenerator.FindApiTypeInfo(buildData, this, caller);
if (apiType != null)
{
- if (!apiType.IsInited)
- apiType.Init(buildData);
+ apiType.EnsureInited(buildData);
return apiType.IsPod;
}
diff --git a/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs b/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs
index e2d01a820..ce39eb3a9 100644
--- a/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs
+++ b/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs
@@ -46,22 +46,35 @@ namespace Flax.Build
var outputPath = Path.GetDirectoryName(buildData.Target.GetOutputFilePath(buildOptions));
var outputFile = Path.Combine(outputPath, binaryModuleName + ".CSharp.dll");
var outputDocFile = Path.Combine(outputPath, binaryModuleName + ".CSharp.xml");
- string monoRoot, exePath;
+ string monoRoot, monoPath, cscPath;
switch (buildPlatform)
{
case TargetPlatform.Windows:
+ {
monoRoot = Path.Combine(Globals.EngineRoot, "Source", "Platforms", "Editor", "Windows", "Mono");
- exePath = Path.Combine(monoRoot, "bin", "mono.exe");
+
+ // Prefer installed Roslyn C# compiler over Mono one
+ monoPath = null;
+ cscPath = Path.Combine(Path.GetDirectoryName(Deploy.VCEnvironment.MSBuildPath), "Roslyn", "csc.exe");
+
+ if (!File.Exists(cscPath))
+ {
+ // Fallback to Mono binaries
+ monoPath = Path.Combine(monoRoot, "bin", "mono.exe");
+ cscPath = Path.Combine(monoRoot, "lib", "mono", "4.5", "csc.exe");
+ }
break;
+ }
case TargetPlatform.Linux:
monoRoot = Path.Combine(Globals.EngineRoot, "Source", "Platforms", "Editor", "Linux", "Mono");
- exePath = Path.Combine(monoRoot, "bin", "mono");
+ monoPath = Path.Combine(monoRoot, "bin", "mono");
+ cscPath = Path.Combine(monoRoot, "lib", "mono", "4.5", "csc.exe");
break;
default: throw new InvalidPlatformException(buildPlatform);
}
- var cscPath = Path.Combine(monoRoot, "lib", "mono", "4.5", "csc.exe");
var referenceAssemblies = Path.Combine(monoRoot, "lib", "mono", "4.5-api");
var references = new HashSet(buildOptions.ScriptingAPI.FileReferences);
+
foreach (var module in binaryModule)
{
if (!buildData.Modules.TryGetValue(module, out var moduleBuildOptions))
@@ -147,11 +160,23 @@ namespace Flax.Build
task.PrerequisiteFiles.AddRange(references);
task.ProducedFiles.Add(outputFile);
task.WorkingDirectory = workspaceRoot;
- task.CommandPath = exePath;
- task.CommandArguments = $"\"{cscPath}\" /noconfig @\"{responseFile}\"";
task.InfoMessage = "Compiling " + outputFile;
task.Cost = task.PrerequisiteFiles.Count;
+ if (monoPath != null)
+ {
+ task.CommandPath = monoPath;
+ task.CommandArguments = $"\"{cscPath}\" /noconfig @\"{responseFile}\"";
+ }
+ else
+ {
+ // The "/shared" flag enables the compiler server support:
+ // https://github.com/dotnet/roslyn/blob/main/docs/compilers/Compiler%20Server.md
+
+ task.CommandPath = cscPath;
+ task.CommandArguments = $"/noconfig /shared @\"{responseFile}\"";
+ }
+
// Copy referenced assemblies
foreach (var reference in buildOptions.ScriptingAPI.FileReferences)
{
diff --git a/Source/Tools/Flax.Build/Deploy/Configuration.cs b/Source/Tools/Flax.Build/Deploy/Configuration.cs
index 7cf30ccd6..aa97933f4 100644
--- a/Source/Tools/Flax.Build/Deploy/Configuration.cs
+++ b/Source/Tools/Flax.Build/Deploy/Configuration.cs
@@ -4,6 +4,12 @@ namespace Flax.Build
{
public static partial class Configuration
{
+ ///
+ /// Package deployment output path.
+ ///
+ [CommandLine("deployOutput", "Package deployment output path.")]
+ public static string DeployOutput;
+
///
/// Builds and packages the editor.
///
diff --git a/Source/Tools/Flax.Build/Deploy/Deployer.cs b/Source/Tools/Flax.Build/Deploy/Deployer.cs
index 9b6ac7657..ce954a5f0 100644
--- a/Source/Tools/Flax.Build/Deploy/Deployer.cs
+++ b/Source/Tools/Flax.Build/Deploy/Deployer.cs
@@ -16,6 +16,7 @@ namespace Flax.Deploy
public static int VersionMajor;
public static int VersionMinor;
public static int VersionBuild;
+ public static TargetConfiguration[] Configurations;
public static bool Run()
{
@@ -64,6 +65,8 @@ namespace Flax.Deploy
static void Initialize()
{
+ Configurations = Configuration.BuildConfigurations != null ? Configuration.BuildConfigurations : new[] { TargetConfiguration.Debug, TargetConfiguration.Development, TargetConfiguration.Release };
+
// Read the current engine version
var engineVersion = EngineTarget.EngineVersion;
VersionMajor = engineVersion.Major;
@@ -81,9 +84,12 @@ namespace Flax.Deploy
Utilities.WriteFileIfChanged(Path.Combine(Globals.EngineRoot, "Source/Engine/Core/Config.Gen.h"), buildConfigHeader.ToString());
// Prepare the package output
- PackageOutputPath = Path.Combine(Globals.EngineRoot, string.Format("Package_{0}_{1:00}_{2:00000}", VersionMajor, VersionMinor, VersionBuild));
- Utilities.DirectoryDelete(PackageOutputPath);
- Directory.CreateDirectory(PackageOutputPath);
+ if (string.IsNullOrEmpty(Configuration.DeployOutput))
+ PackageOutputPath = Path.Combine(Globals.EngineRoot, string.Format("Package_{0}_{1:00}_{2:00000}", VersionMajor, VersionMinor, VersionBuild));
+ else
+ PackageOutputPath = Configuration.DeployOutput;
+ if (!Directory.Exists(PackageOutputPath))
+ Directory.CreateDirectory(PackageOutputPath);
Log.Info(string.Empty);
Log.Info(string.Empty);
@@ -104,9 +110,10 @@ namespace Flax.Deploy
private static void BuildEditor()
{
var targetPlatform = Platform.BuildPlatform.Target;
- FlaxBuild.Build(Globals.EngineRoot, "FlaxEditor", targetPlatform, TargetArchitecture.x64, TargetConfiguration.Debug);
- FlaxBuild.Build(Globals.EngineRoot, "FlaxEditor", targetPlatform, TargetArchitecture.x64, TargetConfiguration.Development);
- FlaxBuild.Build(Globals.EngineRoot, "FlaxEditor", targetPlatform, TargetArchitecture.x64, TargetConfiguration.Release);
+ foreach (var configuration in Configurations)
+ {
+ FlaxBuild.Build(Globals.EngineRoot, "FlaxEditor", targetPlatform, TargetArchitecture.x64, configuration);
+ }
}
private static bool CannotBuildPlatform(TargetPlatform platform)
@@ -129,9 +136,10 @@ namespace Flax.Deploy
{
if (Platform.IsPlatformSupported(platform, architecture))
{
- FlaxBuild.Build(Globals.EngineRoot, "FlaxGame", platform, architecture, TargetConfiguration.Debug);
- FlaxBuild.Build(Globals.EngineRoot, "FlaxGame", platform, architecture, TargetConfiguration.Development);
- FlaxBuild.Build(Globals.EngineRoot, "FlaxGame", platform, architecture, TargetConfiguration.Release);
+ foreach (var configuration in Configurations)
+ {
+ FlaxBuild.Build(Globals.EngineRoot, "FlaxGame", platform, architecture, configuration);
+ }
}
}
diff --git a/Source/Tools/Flax.Build/Deploy/Deployment.Editor.cs b/Source/Tools/Flax.Build/Deploy/Deployment.Editor.cs
index 33dbdbb78..60c2da62e 100644
--- a/Source/Tools/Flax.Build/Deploy/Deployment.Editor.cs
+++ b/Source/Tools/Flax.Build/Deploy/Deployment.Editor.cs
@@ -34,15 +34,15 @@ namespace Flax.Deploy
// Prepare
RootPath = Globals.EngineRoot;
OutputPath = Path.Combine(Deployer.PackageOutputPath, "Editor");
+ Utilities.DirectoryDelete(OutputPath);
Directory.CreateDirectory(OutputPath);
Log.Info(string.Empty);
Log.Info("Deploy editor files");
Log.Info(string.Empty);
// Deploy binaries
- DeployEditorBinaries(TargetConfiguration.Debug);
- DeployEditorBinaries(TargetConfiguration.Development);
- DeployEditorBinaries(TargetConfiguration.Release);
+ foreach (var configuration in Deployer.Configurations)
+ DeployEditorBinaries(configuration);
{
var binariesSubDir = "Binaries/Tools";
var src = Path.Combine(RootPath, binariesSubDir);
@@ -130,12 +130,14 @@ namespace Flax.Deploy
{
// Use system tool (preserves executable file attributes and link files)
editorPackageZipPath = Path.Combine(Deployer.PackageOutputPath, "FlaxEditorLinux.zip");
+ Utilities.FileDelete(editorPackageZipPath);
Utilities.Run("zip", "Editor.zip -r .", null, OutputPath, Utilities.RunOptions.None);
File.Move(Path.Combine(OutputPath, "Editor.zip"), editorPackageZipPath);
}
else
{
editorPackageZipPath = Path.Combine(Deployer.PackageOutputPath, "Editor.zip");
+ Utilities.FileDelete(editorPackageZipPath);
using (ZipFile zip = new ZipFile())
{
zip.AddDirectory(OutputPath);
@@ -152,6 +154,7 @@ namespace Flax.Deploy
{
Log.Info("Compressing editor debug symbols files...");
editorPackageZipPath = Path.Combine(Deployer.PackageOutputPath, "EditorDebugSymbols.zip");
+ Utilities.FileDelete(editorPackageZipPath);
using (ZipFile zip = new ZipFile())
{
zip.AddDirectory(Path.Combine(Deployer.PackageOutputPath, "EditorDebugSymbols"));
diff --git a/Source/Tools/Flax.Build/Deploy/Deployment.Platforms.cs b/Source/Tools/Flax.Build/Deploy/Deployment.Platforms.cs
index e9fc98acc..8c30beda1 100644
--- a/Source/Tools/Flax.Build/Deploy/Deployment.Platforms.cs
+++ b/Source/Tools/Flax.Build/Deploy/Deployment.Platforms.cs
@@ -24,6 +24,7 @@ namespace Flax.Deploy
string platformName = platform.ToString();
string src = Path.Combine(platformsRoot, platformName);
string dst = Path.Combine(Deployer.PackageOutputPath, platformName);
+ Utilities.DirectoryDelete(dst);
// Deploy files
{
@@ -69,6 +70,7 @@ namespace Flax.Deploy
Log.Info("Compressing platform files...");
var packageZipPath = Path.Combine(Deployer.PackageOutputPath, platformName + ".zip");
+ Utilities.FileDelete(packageZipPath);
using (ZipFile zip = new ZipFile())
{
zip.AddDirectory(dst);