Merge branch 'new-content-creations' of https://github.com/Menotdan/FlaxEngine into Menotdan-new-content-creations
This commit is contained in:
181
Source/Editor/Content/Create/PrefabCreateEntry.cs
Normal file
181
Source/Editor/Content/Create/PrefabCreateEntry.cs
Normal file
@@ -0,0 +1,181 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using Object = FlaxEngine.Object;
|
||||
|
||||
namespace FlaxEditor.Content.Create
|
||||
{
|
||||
/// <summary>
|
||||
/// Prefab asset creating handler. Allows to specify base actor to use as the root.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.Create.CreateFileEntry" />
|
||||
public class PrefabCreateEntry : CreateFileEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// The create options.
|
||||
/// </summary>
|
||||
public class Options
|
||||
{
|
||||
/// <summary>
|
||||
/// The root actor.
|
||||
/// </summary>
|
||||
[TypeReference(typeof(FlaxEngine.Actor), nameof(IsValid))]
|
||||
[Tooltip("The actor type of the root of the new Prefab.")]
|
||||
public Type RootActorType = typeof(EmptyActor);
|
||||
|
||||
private static bool IsValid(Type type)
|
||||
{
|
||||
return (type.IsPublic || type.IsNestedPublic) && !type.IsAbstract && !type.IsGenericType;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Options _options = new Options();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object Settings => _options;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PrefabCreateEntry"/> class.
|
||||
/// </summary>
|
||||
/// <param name="resultUrl">The result file url.</param>
|
||||
public PrefabCreateEntry(string resultUrl)
|
||||
: base("Settings", resultUrl)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Create()
|
||||
{
|
||||
if (_options.RootActorType == null)
|
||||
_options.RootActorType = typeof(EmptyActor);
|
||||
|
||||
ScriptType actorType = new ScriptType(_options.RootActorType);
|
||||
|
||||
Actor actor = null;
|
||||
try
|
||||
{
|
||||
actor = actorType.CreateInstance() as Actor;
|
||||
Object.Destroy(actor, 20.0f);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Editor.LogError("Failed to create prefab with root actor type: " + actorType.Name);
|
||||
Editor.LogWarning(ex);
|
||||
return true;
|
||||
}
|
||||
|
||||
return PrefabManager.CreatePrefab(actor, ResultUrl, true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Widget asset creating handler. Allows to specify base UIControl to use as the root.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.Create.CreateFileEntry" />
|
||||
public class WidgetCreateEntry : CreateFileEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// The create options.
|
||||
/// </summary>
|
||||
public class Options
|
||||
{
|
||||
/// <summary>
|
||||
/// Which mode is used to initialize this widget.
|
||||
/// </summary>
|
||||
public enum WidgetMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Initialize the widget with a UICanvas.
|
||||
/// </summary>
|
||||
Canvas,
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the widget with a UIControl.
|
||||
/// </summary>
|
||||
Control
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The mode used to initialize the widget.
|
||||
/// </summary>
|
||||
[Tooltip("Whether to initialize the widget with a canvas or a control.")]
|
||||
public WidgetMode WidgetInitializationMode = WidgetMode.Canvas;
|
||||
|
||||
bool ShowRoot => WidgetInitializationMode == WidgetMode.Control;
|
||||
|
||||
/// <summary>
|
||||
/// The root control.
|
||||
/// </summary>
|
||||
[TypeReference(typeof(Control), nameof(IsValid))]
|
||||
[Tooltip("The control type of the root of the new Widget's root control."), VisibleIf(nameof(ShowRoot))]
|
||||
public Type RootControlType = typeof(Panel);
|
||||
|
||||
private static bool IsValid(Type type)
|
||||
{
|
||||
return (type.IsPublic || type.IsNestedPublic) && !type.IsAbstract && !type.IsGenericType;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Options _options = new Options();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object Settings => _options;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WidgetCreateEntry"/> class.
|
||||
/// </summary>
|
||||
/// <param name="resultUrl">The result file url.</param>
|
||||
public WidgetCreateEntry(string resultUrl)
|
||||
: base("Settings", resultUrl)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Create()
|
||||
{
|
||||
Actor actor = null;
|
||||
|
||||
if (_options.WidgetInitializationMode == Options.WidgetMode.Control)
|
||||
{
|
||||
if (_options.RootControlType == null)
|
||||
_options.RootControlType = typeof(Control);
|
||||
|
||||
ScriptType controlType = new ScriptType(_options.RootControlType);
|
||||
|
||||
Control control = null;
|
||||
try
|
||||
{
|
||||
control = controlType.CreateInstance() as Control;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Editor.LogError("Failed to create widget with root control type: " + controlType.Name);
|
||||
Editor.LogWarning(ex);
|
||||
return true;
|
||||
}
|
||||
|
||||
UIControl newControl = new UIControl();
|
||||
newControl.Control = control;
|
||||
|
||||
actor = newControl;
|
||||
}
|
||||
else if (_options.WidgetInitializationMode == Options.WidgetMode.Canvas)
|
||||
{
|
||||
actor = new UICanvas();
|
||||
}
|
||||
|
||||
if (actor == null)
|
||||
{
|
||||
Editor.LogError("Failed to create widget. Final actor was null.");
|
||||
return true;
|
||||
}
|
||||
|
||||
Object.Destroy(actor, 20.0f);
|
||||
|
||||
return PrefabManager.CreatePrefab(actor, ResultUrl, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,32 @@ namespace FlaxEditor.Content
|
||||
/// <inheritdoc />
|
||||
public override SpriteHandle DefaultThumbnail => SpriteHandle.Invalid;
|
||||
|
||||
private string _cachedTypeDescription = null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string TypeDescription
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_cachedTypeDescription != null)
|
||||
return _cachedTypeDescription;
|
||||
|
||||
Prefab prefab = FlaxEngine.Content.LoadAsync<Prefab>(ID);
|
||||
if (prefab.WaitForLoaded(5000))
|
||||
{
|
||||
_cachedTypeDescription = "Prefab";
|
||||
}
|
||||
|
||||
Actor root = prefab.GetDefaultInstance();
|
||||
if (root is UIControl or UICanvas)
|
||||
_cachedTypeDescription = "Widget";
|
||||
else
|
||||
_cachedTypeDescription = "Prefab";
|
||||
|
||||
return _cachedTypeDescription;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool IsOfType(Type type)
|
||||
{
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
using System;
|
||||
using FlaxEditor.Content.Create;
|
||||
using FlaxEditor.Content.Thumbnails;
|
||||
using FlaxEditor.GUI.ContextMenu;
|
||||
using FlaxEditor.GUI.Timeline;
|
||||
using FlaxEditor.GUI.Timeline.Tracks;
|
||||
using FlaxEditor.Viewport.Previews;
|
||||
using FlaxEditor.Windows;
|
||||
using FlaxEditor.Windows.Assets;
|
||||
@@ -48,6 +51,63 @@ namespace FlaxEditor.Content
|
||||
Editor.Instance.ContentImporting.Create(new ParticleEmitterCreateEntry(outputPath));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnContentWindowContextMenu(ContextMenu menu, ContentItem item)
|
||||
{
|
||||
base.OnContentWindowContextMenu(menu, item);
|
||||
|
||||
if (item is BinaryAssetItem binaryAssetItem)
|
||||
{
|
||||
var button = menu.AddButton("Create Particle System", CreateParticleSystemClicked);
|
||||
button.Tag = binaryAssetItem;
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateParticleSystemClicked(ContextMenuButton obj)
|
||||
{
|
||||
var binaryAssetItem = (BinaryAssetItem)obj.Tag;
|
||||
CreateParticleSystem(binaryAssetItem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the particle system from the given particle emitter.
|
||||
/// </summary>
|
||||
/// <param name="emitterItem">The particle emitter item to use as a base for the particle system.</param>
|
||||
public static void CreateParticleSystem(BinaryAssetItem emitterItem)
|
||||
{
|
||||
var particleSystemName = emitterItem.ShortName + " Particle System";
|
||||
var particleSystemProxy = Editor.Instance.ContentDatabase.GetProxy<ParticleSystem>();
|
||||
Editor.Instance.Windows.ContentWin.NewItem(particleSystemProxy, null, item => OnParticleSystemCreated(item, emitterItem), particleSystemName);
|
||||
}
|
||||
|
||||
private static void OnParticleSystemCreated(ContentItem item, BinaryAssetItem particleItem)
|
||||
{
|
||||
var assetItem = (AssetItem)item;
|
||||
var particleSystem = FlaxEngine.Content.LoadAsync<ParticleSystem>(assetItem.ID);
|
||||
if (particleSystem == null || particleSystem.WaitForLoaded())
|
||||
{
|
||||
Editor.LogError("Failed to load created particle system.");
|
||||
return;
|
||||
}
|
||||
|
||||
ParticleEmitter emitter = FlaxEngine.Content.LoadAsync<ParticleEmitter>(particleItem.ID);
|
||||
if (emitter == null || emitter.WaitForLoaded())
|
||||
{
|
||||
Editor.LogError("Failed to load base particle emitter.");
|
||||
}
|
||||
|
||||
ParticleSystemPreview tempPreview = new ParticleSystemPreview(false);
|
||||
ParticleSystemTimeline timeline = new ParticleSystemTimeline(tempPreview);
|
||||
timeline.Load(particleSystem);
|
||||
|
||||
var track = (ParticleEmitterTrack)timeline.NewTrack(ParticleEmitterTrack.GetArchetype());
|
||||
track.Asset = emitter;
|
||||
track.TrackMedia.DurationFrames = timeline.DurationFrames;
|
||||
track.Rename(particleItem.ShortName);
|
||||
timeline.AddTrack(track);
|
||||
timeline.Save(particleSystem);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnThumbnailDrawPrepare(ThumbnailRequest request)
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using FlaxEditor.Content.Create;
|
||||
using FlaxEditor.Content.Thumbnails;
|
||||
using FlaxEditor.Viewport.Previews;
|
||||
using FlaxEditor.Windows;
|
||||
@@ -86,30 +87,21 @@ namespace FlaxEditor.Content
|
||||
/// <inheritdoc />
|
||||
public override void Create(string outputPath, object arg)
|
||||
{
|
||||
bool resetTransform = false;
|
||||
var transform = Transform.Identity;
|
||||
if (!(arg is Actor actor))
|
||||
{
|
||||
// Create default prefab root object
|
||||
actor = new EmptyActor
|
||||
{
|
||||
Name = "Root"
|
||||
};
|
||||
|
||||
// Cleanup it after usage
|
||||
Object.Destroy(actor, 20.0f);
|
||||
Editor.Instance.ContentImporting.Create(new PrefabCreateEntry(outputPath));
|
||||
return;
|
||||
}
|
||||
else if (actor.HasScene)
|
||||
{
|
||||
// Create prefab with identity transform so the actor instance on a level will have it customized
|
||||
resetTransform = true;
|
||||
transform = actor.LocalTransform;
|
||||
actor.LocalTransform = Transform.Identity;
|
||||
}
|
||||
|
||||
PrefabManager.CreatePrefab(actor, outputPath, true);
|
||||
if (resetTransform)
|
||||
actor.LocalTransform = transform;
|
||||
actor.LocalTransform = transform;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -251,18 +243,8 @@ namespace FlaxEditor.Content
|
||||
/// <inheritdoc />
|
||||
public override void Create(string outputPath, object arg)
|
||||
{
|
||||
// Create prefab with UI Control
|
||||
var actor = new UIControl
|
||||
{
|
||||
Name = Path.GetFileNameWithoutExtension(outputPath),
|
||||
StaticFlags = StaticFlags.None,
|
||||
};
|
||||
actor.Control = new Button
|
||||
{
|
||||
Text = "Button",
|
||||
};
|
||||
PrefabManager.CreatePrefab(actor, outputPath, false);
|
||||
Object.Destroy(actor, 20.0f);
|
||||
Editor.Instance.ContentImporting.Create(new WidgetCreateEntry(outputPath));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
using System;
|
||||
using FlaxEditor.Content.Thumbnails;
|
||||
using FlaxEditor.GUI.ContextMenu;
|
||||
using FlaxEditor.Viewport.Previews;
|
||||
using FlaxEditor.Windows;
|
||||
using FlaxEditor.Windows.Assets;
|
||||
@@ -39,6 +40,57 @@ namespace FlaxEditor.Content
|
||||
/// <inheritdoc />
|
||||
public override Type AssetType => typeof(SkinnedModel);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnContentWindowContextMenu(ContextMenu menu, ContentItem item)
|
||||
{
|
||||
base.OnContentWindowContextMenu(menu, item);
|
||||
|
||||
if (item is BinaryAssetItem binaryAssetItem)
|
||||
{
|
||||
var button = menu.AddButton("Create Animation Graph", CreateAnimationGraphClicked);
|
||||
button.Tag = binaryAssetItem;
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateAnimationGraphClicked(ContextMenuButton obj)
|
||||
{
|
||||
var binaryAssetItem = (BinaryAssetItem)obj.Tag;
|
||||
CreateAnimationGraph(binaryAssetItem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the animation graph from the given particle emitter.
|
||||
/// </summary>
|
||||
/// <param name="skinnedModelItem">The skinned model item to use as the base model for the animation graph.</param>
|
||||
public static void CreateAnimationGraph(BinaryAssetItem skinnedModelItem)
|
||||
{
|
||||
var animationGraphName = skinnedModelItem.ShortName + " Graph";
|
||||
var animationGraphProxy = Editor.Instance.ContentDatabase.GetProxy<AnimationGraph>();
|
||||
Editor.Instance.Windows.ContentWin.NewItem(animationGraphProxy, null, item => OnAnimationGraphCreated(item, skinnedModelItem), animationGraphName);
|
||||
}
|
||||
|
||||
private static void OnAnimationGraphCreated(ContentItem item, BinaryAssetItem skinnedModelItem)
|
||||
{
|
||||
var skinnedModel = FlaxEngine.Content.LoadAsync<SkinnedModel>(skinnedModelItem.ID);
|
||||
if (skinnedModel == null || skinnedModel.WaitForLoaded())
|
||||
{
|
||||
Editor.LogError("Failed to load base skinned model.");
|
||||
}
|
||||
|
||||
// Hack the animation graph window to modify the base model of the animation graph.
|
||||
AnimationGraphWindow win = new AnimationGraphWindow(Editor.Instance, item as AssetItem);
|
||||
win.Show();
|
||||
|
||||
// Ensure the window knows the asset is loaded so we can save it later.
|
||||
win.Asset.WaitForLoaded();
|
||||
win.Update(0); // Call Update() to refresh the loaded flag.
|
||||
|
||||
win.SetBaseModel(skinnedModel);
|
||||
win.Surface.MarkAsEdited();
|
||||
win.Save();
|
||||
win.Close();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnThumbnailDrawPrepare(ThumbnailRequest request)
|
||||
{
|
||||
|
||||
@@ -295,6 +295,15 @@ namespace FlaxEditor.Windows.Assets
|
||||
base.SetParameter(index, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the base model of the animation graph this window is editing.
|
||||
/// </summary>
|
||||
/// <param name="baseModel">The new base model.</param>
|
||||
public void SetBaseModel(SkinnedModel baseModel)
|
||||
{
|
||||
_properties.BaseModel = baseModel;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void UnlinkItem()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user