diff --git a/Source/Editor/Content/Proxy/ScriptProxy.cs b/Source/Editor/Content/Proxy/ScriptProxy.cs
index f688f37df..d728dcc38 100644
--- a/Source/Editor/Content/Proxy/ScriptProxy.cs
+++ b/Source/Editor/Content/Proxy/ScriptProxy.cs
@@ -69,8 +69,7 @@ namespace FlaxEditor.Content
///
public override bool IsFileNameValid(string filename)
{
- // Scripts cannot start with digit.
- if (Char.IsDigit(filename[0]))
+ if (char.IsDigit(filename[0]))
return false;
if (filename.Equals("Script"))
return false;
diff --git a/Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs b/Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs
index e03ccb331..63374361d 100644
--- a/Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs
+++ b/Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs
@@ -3,6 +3,8 @@
using System;
using System.Collections;
using System.Collections.Generic;
+using System.IO;
+using System.Linq;
using FlaxEditor.Actions;
using FlaxEditor.Content;
using FlaxEditor.GUI;
@@ -16,6 +18,27 @@ using Object = FlaxEngine.Object;
namespace FlaxEditor.CustomEditors.Dedicated
{
+ internal class NewScriptItem : ItemsListContextMenu.Item
+ {
+ private string _scriptName;
+
+ public string ScriptName
+ {
+ get => _scriptName;
+ set
+ {
+ _scriptName = value;
+ Name = $"Create script '{value}'";
+ }
+ }
+
+ public NewScriptItem(string scriptName)
+ {
+ ScriptName = scriptName;
+ TooltipText = "Create a new script";
+ }
+ }
+
///
/// Drag and drop scripts area control.
///
@@ -74,7 +97,43 @@ namespace FlaxEditor.CustomEditors.Dedicated
{
cm.AddItem(new TypeSearchPopup.TypeItemView(scripts[i]));
}
- cm.ItemClicked += item => AddScript((ScriptType)item.Tag);
+ cm.TextChanged += text =>
+ {
+ if (!IsValidScriptName(text))
+ return;
+ if (!cm.ItemsPanel.Children.Any(x => x.Visible && x is not NewScriptItem))
+ {
+ // If there are no visible items, that means the search failed so we can find the create script button or create one if it's the first time
+ var newScriptItem = (NewScriptItem)cm.ItemsPanel.Children.FirstOrDefault(x => x is NewScriptItem);
+ if (newScriptItem != null)
+ {
+ newScriptItem.Visible = true;
+ newScriptItem.ScriptName = text;
+ }
+ else
+ {
+ cm.AddItem(new NewScriptItem(text));
+ }
+ }
+ else
+ {
+ // Make sure to hide the create script button if there
+ var newScriptItem = cm.ItemsPanel.Children.FirstOrDefault(x => x is NewScriptItem);
+ if (newScriptItem != null)
+ newScriptItem.Visible = false;
+ }
+ };
+ cm.ItemClicked += item =>
+ {
+ if (item.Tag is ScriptType script)
+ {
+ AddScript(script);
+ }
+ else if (item is NewScriptItem newScriptItem)
+ {
+ CreateScript(newScriptItem);
+ }
+ };
cm.SortItems();
cm.Show(this, button.BottomLeft - new Float2((cm.Width - button.Width) / 2, 0));
}
@@ -113,6 +172,19 @@ namespace FlaxEditor.CustomEditors.Dedicated
return false;
}
+ private static bool IsValidScriptName(string text)
+ {
+ if (string.IsNullOrEmpty(text))
+ return false;
+ if (text.Contains(' '))
+ return false;
+ if (char.IsDigit(text[0]))
+ return false;
+ if (text.Any(c => !char.IsLetterOrDigit(c) && c != '_'))
+ return false;
+ return Editor.Instance.ContentDatabase.GetProxy("cs").IsFileNameValid(text);
+ }
+
///
public override DragDropEffect OnDragEnter(ref Float2 location, DragData data)
{
@@ -163,6 +235,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
if (_dragScripts.HasValidDrag)
{
result = _dragScripts.Effect;
+
AddScripts(_dragScripts.Objects);
}
else if (_dragAssets.HasValidDrag)
@@ -177,7 +250,43 @@ namespace FlaxEditor.CustomEditors.Dedicated
return result;
}
- private void AddScript(ScriptType item)
+ private void CreateScript(NewScriptItem item)
+ {
+ ScriptsEditor.NewScriptName = item.ScriptName;
+ var paths = Directory.GetFiles(Globals.ProjectSourceFolder, "*.Build.cs");
+
+ string moduleName = null;
+ foreach (var p in paths)
+ {
+ var file = File.ReadAllText(p);
+ if (!file.Contains("GameProjectTarget"))
+ continue; // Skip
+
+ if (file.Contains("Modules.Add(\"Game\")"))
+ {
+ // Assume Game represents the main game module
+ moduleName = "Game";
+ break;
+ }
+ }
+
+ // Ensure the path slashes are correct for the OS
+ var correctedPath = Path.GetFullPath(Globals.ProjectSourceFolder);
+ if (string.IsNullOrEmpty(moduleName))
+ {
+ var error = FileSystem.ShowBrowseFolderDialog(Editor.Instance.Windows.MainWindow, correctedPath, "Select a module folder to put the new script in", out moduleName);
+ if (error)
+ return;
+ }
+ var path = Path.Combine(Globals.ProjectSourceFolder, moduleName, item.ScriptName + ".cs");
+ Editor.Instance.ContentDatabase.GetProxy("cs").Create(path, null);
+ }
+
+ ///
+ /// Attach a script to the actor.
+ ///
+ /// The script.
+ public void AddScript(ScriptType item)
{
var list = new List(1) { item };
AddScripts(list);
@@ -491,6 +600,11 @@ namespace FlaxEditor.CustomEditors.Dedicated
///
public override IEnumerable