从旧版中移植,Prefab未确认
This commit is contained in:
82
Convention/[Visual]/Workflow/GraphInputWindow.cs
Normal file
82
Convention/[Visual]/Workflow/GraphInputWindow.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Convention.WindowsUI;
|
||||
using Convention.WindowsUI.Variant;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace Convention.Workflow
|
||||
{
|
||||
public class GraphInputWindow : MonoSingleton<GraphInputWindow>, ITitle, IText
|
||||
{
|
||||
[Resources, SerializeField, OnlyNotNullMode] private Text Title;
|
||||
[Resources, SerializeField, OnlyNotNullMode] private Text Description;
|
||||
[Resources, SerializeField, OnlyNotNullMode] private ModernUIButton AddContentInput;
|
||||
|
||||
[Resources, SerializeField, HopeNotNull, Header(nameof(HierarchyWindow))] private HierarchyWindow MyHierarchyWindow;
|
||||
|
||||
private PropertiesWindow.ItemEntry StartNodeInputsTab, FunctionsTab, EndNodeOutputsTab;
|
||||
|
||||
public string title { get => ((ITitle)this.Title).title; set => ((ITitle)this.Title).title = value; }
|
||||
public string text { get => ((IText)this.Description).text; set => ((IText)this.Description).text = value; }
|
||||
|
||||
private class TitleClass : IHierarchyItemTitle
|
||||
{
|
||||
[InspectorDraw(InspectorDrawType.Text, false, false)]
|
||||
public string title;
|
||||
|
||||
public TitleClass(string title)
|
||||
{
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public string HierarchyItemTitle => title;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
AddContentInput.AddListener(() =>
|
||||
{
|
||||
SharedModule.instance.OpenCustomMenu(this.transform as RectTransform, new SharedModule.CallbackData("test", go => { }));
|
||||
});
|
||||
Architecture.RegisterWithDuplicateAllow(typeof(GraphInputWindow), this, () =>
|
||||
{
|
||||
StartNodeInputsTab = MyHierarchyWindow.CreateRootItemEntryWithBinders(new TitleClass(nameof(StartNodeInputsTab)))[0];
|
||||
StartNodeInputsTab.GetHierarchyItem().title = WorkflowManager.Transformer("StartNodes");
|
||||
FunctionsTab = MyHierarchyWindow.CreateRootItemEntryWithBinders(new TitleClass(nameof(FunctionsTab)))[0];
|
||||
FunctionsTab.GetHierarchyItem().title = WorkflowManager.Transformer("Functions");
|
||||
EndNodeOutputsTab = MyHierarchyWindow.CreateRootItemEntryWithBinders(new TitleClass(nameof(EndNodeOutputsTab)))[0];
|
||||
EndNodeOutputsTab.GetHierarchyItem().title = WorkflowManager.Transformer("EndNodes");
|
||||
}, typeof(HierarchyWindow));
|
||||
}
|
||||
private void Reset()
|
||||
{
|
||||
MyHierarchyWindow = GetComponent<HierarchyWindow>();
|
||||
}
|
||||
|
||||
public PropertiesWindow.ItemEntry RegisterOnHierarchyWindow(NodeInfo info)
|
||||
{
|
||||
PropertiesWindow.ItemEntry item = null;
|
||||
if (info is StartNodeInfo)
|
||||
{
|
||||
item = StartNodeInputsTab.GetHierarchyItem().CreateSubPropertyItemWithBinders(info)[0];
|
||||
}
|
||||
else if (info is EndNodeInfo)
|
||||
{
|
||||
item = EndNodeOutputsTab.GetHierarchyItem().CreateSubPropertyItemWithBinders(info)[0];
|
||||
}
|
||||
else if (info is StepNodeInfo sNode)
|
||||
{
|
||||
var parentItem = FunctionsTab.GetHierarchyItem();
|
||||
var menuEntry = parentItem.Entry.GetChilds().Find(x => (x.GetHierarchyItem().target as TitleClass).title == sNode.funcname);
|
||||
if (menuEntry == null)
|
||||
{
|
||||
menuEntry = parentItem.CreateSubPropertyItemWithBinders(new TitleClass(sNode.funcname))[0];
|
||||
}
|
||||
item = menuEntry.GetHierarchyItem().CreateSubPropertyItemWithBinders(info)[0];
|
||||
}
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
11
Convention/[Visual]/Workflow/GraphInputWindow.cs.meta
Normal file
11
Convention/[Visual]/Workflow/GraphInputWindow.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 628e8952d5d14ea46b193b11d1d15fee
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
23
Convention/[Visual]/Workflow/GraphInspector.cs
Normal file
23
Convention/[Visual]/Workflow/GraphInspector.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Convention.WindowsUI;
|
||||
using Convention.WindowsUI.Variant;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace Convention.Workflow
|
||||
{
|
||||
public class GraphInspector : MonoSingleton<GraphInspector>, ITitle, IText
|
||||
{
|
||||
[Resources, SerializeField, OnlyNotNullMode] private Text Title;
|
||||
|
||||
public string title { get => ((ITitle)this.Title).title; set => ((ITitle)this.Title).title = value; }
|
||||
public string text { get => ((IText)this.Title).text; set => ((IText)this.Title).text = value; }
|
||||
|
||||
private void Start()
|
||||
{
|
||||
Architecture.RegisterWithDuplicateAllow(typeof(GraphInspector), this, () => { });
|
||||
}
|
||||
}
|
||||
}
|
11
Convention/[Visual]/Workflow/GraphInspector.cs.meta
Normal file
11
Convention/[Visual]/Workflow/GraphInspector.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: facb72df493019b48ba11ef9789a1fae
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
408
Convention/[Visual]/Workflow/Node.cs
Normal file
408
Convention/[Visual]/Workflow/Node.cs
Normal file
@@ -0,0 +1,408 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Convention.WindowsUI;
|
||||
using Convention.WindowsUI.Variant;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace Convention.Workflow
|
||||
{
|
||||
[Serializable, ArgPackage]
|
||||
public class NodeInfo : IHierarchyItemTitle
|
||||
{
|
||||
/// <summary>
|
||||
/// 节点
|
||||
/// </summary>
|
||||
[Setting, Ignore, NonSerialized] public Node node = null;
|
||||
/// <summary>
|
||||
/// 节点ID
|
||||
/// </summary>
|
||||
[Setting] public int nodeID = -1;
|
||||
/// <summary>
|
||||
/// 节点类型
|
||||
/// </summary>
|
||||
[InspectorDraw(InspectorDrawType.Text, false, false, name: "GraphNodeType")]
|
||||
[Setting] public string typename;
|
||||
/// <summary>
|
||||
/// 节点标题
|
||||
/// </summary>
|
||||
[Content] public string title = "";
|
||||
/// <summary>
|
||||
/// 输入映射
|
||||
/// </summary>
|
||||
[Setting] public Dictionary<string, NodeSlotInfo> inmapping = new();
|
||||
/// <summary>
|
||||
/// 输出映射
|
||||
/// </summary>
|
||||
[Setting] public Dictionary<string, NodeSlotInfo> outmapping = new();
|
||||
/// <summary>
|
||||
/// 节点位置
|
||||
/// </summary>
|
||||
[Content] public Vector2 position = Vector2.zero;
|
||||
|
||||
[InspectorDraw(InspectorDrawType.Text, name: "GraphNodeTitle")]
|
||||
public string GraphNodeTitle
|
||||
{
|
||||
get => this.title;
|
||||
set => this.title = node.title = value;
|
||||
}
|
||||
|
||||
string IHierarchyItemTitle.HierarchyItemTitle => title;
|
||||
|
||||
public NodeInfo()
|
||||
{
|
||||
WorkflowManager.Transformer(typename = this.GetType().Name[..^4]);
|
||||
}
|
||||
|
||||
protected virtual NodeInfo CreateTemplate()
|
||||
{
|
||||
return new NodeInfo();
|
||||
}
|
||||
protected virtual void CloneValues([In] NodeInfo clonen)
|
||||
{
|
||||
clonen.nodeID = nodeID;
|
||||
clonen.typename = typename;
|
||||
clonen.title = string.IsNullOrEmpty(title) ? WorkflowManager.Transformer(this.GetType().Name[..^4]) : title;
|
||||
clonen.position = position;
|
||||
foreach (var (key, value) in inmapping)
|
||||
{
|
||||
clonen.inmapping[key] = value.TemplateClone();
|
||||
}
|
||||
foreach (var (key, value) in outmapping)
|
||||
{
|
||||
clonen.outmapping[key] = value.TemplateClone();
|
||||
}
|
||||
}
|
||||
public NodeInfo TemplateClone()
|
||||
{
|
||||
NodeInfo result = CreateTemplate();
|
||||
CloneValues(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Vector2 GetPosition(Transform transform)
|
||||
{
|
||||
Vector3 result = transform.position - WorkflowManager.instance.ContentPlane.transform.position;
|
||||
return new(result.x, result.y);
|
||||
}
|
||||
|
||||
public virtual void CopyFromNode([In] Node node)
|
||||
{
|
||||
nodeID = WorkflowManager.instance.GetGraphNodeID(node);
|
||||
title = node.title;
|
||||
position = GetPosition(node.transform);
|
||||
foreach (var (key, inslot) in node.m_Inmapping)
|
||||
{
|
||||
inmapping[key] = inslot.info;
|
||||
}
|
||||
foreach (var (key, outslot) in node.m_Outmapping)
|
||||
{
|
||||
outmapping[key] = outslot.info;
|
||||
}
|
||||
}
|
||||
|
||||
[return: IsInstantiated(true)]
|
||||
public virtual Node Instantiate()
|
||||
{
|
||||
string key = this.GetType().Name;
|
||||
if (key.EndsWith("Info"))
|
||||
key = key[..^4];
|
||||
var node = GameObject.Instantiate(WorkflowManager.instance.GraphNodePrefabs.FindItem<GameObject>(key)).GetComponent<Node>();
|
||||
return node;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{title}<in.c={(inmapping == null ? 0 : inmapping.Count)}, out.c={(outmapping == null ? 0 : outmapping.Count)}>";
|
||||
}
|
||||
}
|
||||
|
||||
public class Node : WindowsComponent, IOnlyFocusThisOnInspector, ITitle
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[Content]
|
||||
public void DebugLogNodeInfo()
|
||||
{
|
||||
Debug.Log(this.info);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public PropertiesWindow.ItemEntry MyNodeTab;
|
||||
|
||||
private BehaviourContextManager Context;
|
||||
[Resources, OnlyNotNullMode, SerializeField] private Text Title;
|
||||
[Setting]
|
||||
public int SlotHeight = 40, TitleHeight = 50, ExtensionHeight = 0;
|
||||
|
||||
public bool IsStartNode => this.GetType().IsSubclassOf(typeof(StartNode));
|
||||
public bool IsEndNode => this.GetType().IsSubclassOf(typeof(EndNode));
|
||||
|
||||
[Resources, SerializeField, WhenAttribute.Is(nameof(IsStartNode), false), OnlyNotNullMode]
|
||||
private PropertiesWindow InSlotPropertiesWindow;
|
||||
[Resources, SerializeField, WhenAttribute.Is(nameof(IsEndNode), false), OnlyNotNullMode]
|
||||
private PropertiesWindow OutSlotPropertiesWindow;
|
||||
|
||||
private List<PropertiesWindow.ItemEntry> InSlots = new(), OutSlots = new();
|
||||
|
||||
internal Dictionary<string, NodeSlot> m_Inmapping = new();
|
||||
internal Dictionary<string, NodeSlot> m_Outmapping = new();
|
||||
|
||||
[Resources, SerializeField, OnlyNotNullMode] protected BaseWindowPlane InoutContainerPlane;
|
||||
|
||||
[Content, OnlyPlayMode, SerializeField] private string rawTitle;
|
||||
public string title
|
||||
{
|
||||
get => rawTitle;
|
||||
set
|
||||
{
|
||||
rawTitle = value;
|
||||
this.Title.title = WorkflowManager.Transformer(rawTitle);
|
||||
}
|
||||
}
|
||||
|
||||
[Setting, SerializeField] private NodeInfo m_info;
|
||||
public NodeInfo info { get => m_info; private set => m_info = value; }
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
if (Context == null)
|
||||
Context = this.GetOrAddComponent<BehaviourContextManager>();
|
||||
Context.OnPointerDownEvent = BehaviourContextManager.InitializeContextSingleEvent(Context.OnPointerDownEvent, OnPointerDown);
|
||||
Context.OnDragEvent = BehaviourContextManager.InitializeContextSingleEvent(Context.OnDragEvent, OnDrag);
|
||||
Context.OnPointerClickEvent = BehaviourContextManager.InitializeContextSingleEvent(Context.OnPointerClickEvent, PointerRightClickAndOpenMenu);
|
||||
Context.OnEndDragEvent = BehaviourContextManager.InitializeContextSingleEvent(Context.OnEndDragEvent, EndDrag);
|
||||
}
|
||||
|
||||
protected virtual void OnDestroy()
|
||||
{
|
||||
if (InspectorWindow.instance.GetTarget() == this.info)
|
||||
{
|
||||
InspectorWindow.instance.ClearWindow();
|
||||
}
|
||||
MyNodeTab?.Release();
|
||||
}
|
||||
|
||||
public virtual void PointerRightClickAndOpenMenu(PointerEventData pointer)
|
||||
{
|
||||
if (pointer.button == PointerEventData.InputButton.Right)
|
||||
{
|
||||
List<SharedModule.CallbackData> callbacks = new()
|
||||
{
|
||||
new (WorkflowManager.Transformer("Delete"), x =>
|
||||
{
|
||||
WorkflowManager.instance.DestroyNode(this);
|
||||
})
|
||||
};
|
||||
SharedModule.instance.OpenCustomMenu(WorkflowManager.instance.UIFocusObject, callbacks.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPointerDown(PointerEventData _)
|
||||
{
|
||||
if (this.info != null)
|
||||
InspectorWindow.instance.SetTarget(this.info, null);
|
||||
else
|
||||
Debug.LogError($"GraphNode<{this.GetType()}>={this}'s info is not setup", this);
|
||||
}
|
||||
|
||||
public void OnDrag(PointerEventData _)
|
||||
{
|
||||
RefreshImmediate();
|
||||
}
|
||||
|
||||
public void EndDrag(PointerEventData _)
|
||||
{
|
||||
if (Keyboard.current[Key.LeftCtrl].isPressed)
|
||||
{
|
||||
var vec = this.transform.localPosition;
|
||||
float x = Mathf.Round(vec.x / 100);
|
||||
float y = Mathf.Round(vec.y / 100);
|
||||
transform.localPosition = new Vector3(x * 100, y * 100, 0);
|
||||
RefreshImmediate();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void WhenSetup(NodeInfo info)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void SetupFromInfo([In] NodeInfo value, bool isRefresh = true)
|
||||
{
|
||||
if (value != info)
|
||||
{
|
||||
ClearLink();
|
||||
ClearSlots();
|
||||
info = value;
|
||||
this.title = value.title;
|
||||
int nodeID = WorkflowManager.instance.GetGraphNodeID(this);
|
||||
value.nodeID = nodeID;
|
||||
value.node = this;
|
||||
if (isRefresh)
|
||||
{
|
||||
BuildSlots();
|
||||
BuildLink();
|
||||
RefreshPosition();
|
||||
}
|
||||
WhenSetup(info);
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshImmediate()
|
||||
{
|
||||
foreach (var (_, slot) in m_Inmapping)
|
||||
{
|
||||
if (slot != null)
|
||||
slot.SetDirty();
|
||||
}
|
||||
foreach (var (_, slot) in m_Outmapping)
|
||||
{
|
||||
if (slot != null)
|
||||
{
|
||||
foreach (var targetSlot in slot.info.targetSlots)
|
||||
{
|
||||
targetSlot.SetDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public void RefreshPosition()
|
||||
{
|
||||
this.transform.position = new Vector3(info.position.x, info.position.y) + (WorkflowManager.instance.ContentPlane.transform.position);
|
||||
}
|
||||
public void RefreshRectTransform()
|
||||
{
|
||||
this.rectTransform.sizeDelta = new(this.rectTransform.sizeDelta.x, TitleHeight + Mathf.Max(m_Inmapping.Count, m_Outmapping.Count) * SlotHeight + ExtensionHeight);
|
||||
}
|
||||
public virtual void ClearLink()
|
||||
{
|
||||
if (InSlotPropertiesWindow == true)
|
||||
foreach (var (name, slot) in this.m_Inmapping)
|
||||
{
|
||||
NodeSlot.UnlinkAll(slot);
|
||||
slot.SetDirty();
|
||||
}
|
||||
if (OutSlotPropertiesWindow == true)
|
||||
foreach (var (name, slot) in m_Outmapping)
|
||||
{
|
||||
NodeSlot.UnlinkAll(slot);
|
||||
slot.SetDirty();
|
||||
}
|
||||
}
|
||||
public virtual void ClearSlots()
|
||||
{
|
||||
if (this.info == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (InSlotPropertiesWindow == true)
|
||||
{
|
||||
foreach (var slot in this.InSlots)
|
||||
slot.Release();
|
||||
this.m_Inmapping.Clear();
|
||||
}
|
||||
if (OutSlotPropertiesWindow == true)
|
||||
{
|
||||
foreach (var slot in this.OutSlots)
|
||||
slot.Release();
|
||||
OutSlots.Clear();
|
||||
this.m_Outmapping.Clear();
|
||||
}
|
||||
}
|
||||
protected List<PropertiesWindow.ItemEntry> CreateGraphNodeInSlots(int count)
|
||||
{
|
||||
if (InSlotPropertiesWindow == null)
|
||||
throw new InvalidOperationException($"this node is not using {nameof(InSlotPropertiesWindow)}");
|
||||
return InSlotPropertiesWindow.CreateRootItemEntries(count);
|
||||
}
|
||||
protected List<PropertiesWindow.ItemEntry> CreateGraphNodeOutSlots(int count)
|
||||
{
|
||||
if (OutSlotPropertiesWindow == null)
|
||||
throw new InvalidOperationException($"this node is not using {nameof(OutSlotPropertiesWindow)}");
|
||||
return OutSlotPropertiesWindow.CreateRootItemEntries(count);
|
||||
}
|
||||
public virtual void BuildSlots()
|
||||
{
|
||||
if (InSlotPropertiesWindow == true)
|
||||
{
|
||||
int InSlotCount = info.inmapping.Count;
|
||||
InSlots = CreateGraphNodeInSlots(InSlotCount);
|
||||
foreach (var (key, slotInfo) in info.inmapping)
|
||||
{
|
||||
InSlotCount--;
|
||||
var slot = InSlots[InSlotCount].ref_value.GetComponent<NodeSlot>();
|
||||
// 这样真的好吗
|
||||
m_Inmapping[key] = slot;
|
||||
var info = slotInfo.TemplateClone();
|
||||
info.parentNode = this;
|
||||
slot.SetupFromInfo(info);
|
||||
}
|
||||
}
|
||||
if (OutSlotPropertiesWindow == true)
|
||||
{
|
||||
int OutSlotCount = info.outmapping.Count;
|
||||
OutSlots = CreateGraphNodeOutSlots(OutSlotCount);
|
||||
foreach (var (key, slotInfo) in info.outmapping)
|
||||
{
|
||||
OutSlotCount--;
|
||||
var slot = OutSlots[OutSlotCount].ref_value.GetComponent<NodeSlot>();
|
||||
// 通过这种方法规避了重复键, 但是也存在一些特殊的问题
|
||||
m_Outmapping[key] = slot;
|
||||
var info = slotInfo.TemplateClone();
|
||||
info.parentNode = this;
|
||||
slot.SetupFromInfo(info);
|
||||
}
|
||||
}
|
||||
RefreshRectTransform();
|
||||
}
|
||||
public virtual void BuildLink()
|
||||
{
|
||||
if (InSlotPropertiesWindow != null)
|
||||
{
|
||||
foreach (var (slot_name, slot_info) in info.inmapping)
|
||||
{
|
||||
var targetNode = WorkflowManager.instance.GetGraphNode(slot_info.targetNodeID);
|
||||
if (targetNode != null)
|
||||
{
|
||||
NodeSlot.Link(m_Inmapping[slot_name], targetNode.m_Outmapping[slot_info.targetSlotName]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void LinkInslotToOtherNodeOutslot(
|
||||
[In, IsInstantiated(true)] Node other,
|
||||
[In] string slotName,
|
||||
[In] string targetSlotName)
|
||||
{
|
||||
NodeSlot.Link(this.m_Inmapping[slotName], other.m_Outmapping[targetSlotName]);
|
||||
}
|
||||
public void LinkOutslotToOtherNodeInslot(
|
||||
[In, IsInstantiated(true)] Node other,
|
||||
[In] string slotName,
|
||||
[In] string targetSlotName)
|
||||
{
|
||||
NodeSlot.Link(this.m_Outmapping[slotName], other.m_Inmapping[targetSlotName]);
|
||||
}
|
||||
public void UnlinkInslot([In] string slotName)
|
||||
{
|
||||
NodeSlot.UnlinkAll(this.m_Inmapping[slotName]);
|
||||
}
|
||||
public void UnlinkOutslot([In] string slotName)
|
||||
{
|
||||
NodeSlot.UnlinkAll(this.m_Outmapping[slotName]);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, ArgPackage]
|
||||
public class DynamicNodeInfo : NodeInfo
|
||||
{
|
||||
protected override NodeInfo CreateTemplate()
|
||||
{
|
||||
return new DynamicNodeInfo();
|
||||
}
|
||||
}
|
||||
}
|
11
Convention/[Visual]/Workflow/Node.cs.meta
Normal file
11
Convention/[Visual]/Workflow/Node.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93f89afbfd02c054aa2e5c7141eae234
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
340
Convention/[Visual]/Workflow/NodeSlot.cs
Normal file
340
Convention/[Visual]/Workflow/NodeSlot.cs
Normal file
@@ -0,0 +1,340 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Convention.WindowsUI;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace Convention.Workflow
|
||||
{
|
||||
[Serializable, ArgPackage]
|
||||
public class NodeSlotInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 所属的父节点
|
||||
/// </summary>
|
||||
[Ignore, NonSerialized] public Node parentNode = null;
|
||||
/// <summary>
|
||||
/// 所属的插槽
|
||||
/// </summary>
|
||||
[Ignore, NonSerialized] public NodeSlot slot = null;
|
||||
/// <summary>
|
||||
/// 插槽名称
|
||||
/// </summary>
|
||||
public string slotName = "unknown";
|
||||
/// <summary>
|
||||
/// 目标节点
|
||||
/// </summary>
|
||||
[Ignore, NonSerialized]
|
||||
public List<Node> targetNodes = new();
|
||||
/// <summary>
|
||||
/// 目标槽
|
||||
/// </summary>
|
||||
[Ignore, NonSerialized]
|
||||
public List<NodeSlot> targetSlots = new();
|
||||
/// <summary>
|
||||
/// 目标节点ID, 输出节点无效
|
||||
/// </summary>
|
||||
public int targetNodeID = -1;
|
||||
/// <summary>
|
||||
/// 目标插槽名称, 输出节点无效
|
||||
/// </summary>
|
||||
public string targetSlotName = "unknown";
|
||||
/// <summary>
|
||||
/// 类型指示器
|
||||
/// </summary>
|
||||
public string typeIndicator;
|
||||
/// <summary>
|
||||
/// 是否为输入映射插槽
|
||||
/// </summary>
|
||||
public bool IsInmappingSlot;
|
||||
|
||||
public NodeSlotInfo TemplateClone(bool isClearn = true)
|
||||
{
|
||||
NodeSlotInfo result = new()
|
||||
{
|
||||
slotName = slotName,
|
||||
targetNodeID = isClearn ? -1 : this.targetNodeID,
|
||||
targetSlotName = isClearn ? "" : this.targetSlotName,
|
||||
typeIndicator = typeIndicator,
|
||||
IsInmappingSlot = IsInmappingSlot
|
||||
};
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public interface INodeSlotLinkable
|
||||
{
|
||||
public bool LinkTo([In, Opt] NodeSlot other);
|
||||
public bool Linkable([In]NodeSlot other);
|
||||
}
|
||||
|
||||
public class NodeSlot : WindowUIModule, ITitle, INodeSlotLinkable
|
||||
{
|
||||
[Resources, Setting, Tooltip("挂载额外的组件")] public GameObject ExtensionModule;
|
||||
|
||||
//这个缩放因子是最顶层Canvas的变形
|
||||
public const float ScaleFactor = 100;
|
||||
|
||||
public bool Linkable([In] NodeSlot other)
|
||||
{
|
||||
if (this.info.IsInmappingSlot == other.info.IsInmappingSlot)
|
||||
{
|
||||
throw new InvalidOperationException($"{this} and {other} has same mapping type");
|
||||
}
|
||||
if (this.info.typeIndicator != other.info.typeIndicator)
|
||||
{
|
||||
if (!((this.info.typeIndicator == "string" && other.info.typeIndicator == "str") ||
|
||||
(this.info.typeIndicator == "str" && other.info.typeIndicator == "string") ||
|
||||
this.info.typeIndicator.StartsWith("Any", StringComparison.CurrentCultureIgnoreCase) ||
|
||||
other.info.typeIndicator.StartsWith("Any", StringComparison.CurrentCultureIgnoreCase
|
||||
)))
|
||||
throw new InvalidOperationException($"{this}<{this.info.typeIndicator}> and {other}<{other.info.typeIndicator}> has different type indicator");
|
||||
}
|
||||
if (this.info.parentNode == other.info.parentNode)
|
||||
{
|
||||
throw new InvalidOperationException($"{this} and {other} has same parent node<{this.info.parentNode}>");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public static void Link([In] NodeSlot left, [In] NodeSlot right)
|
||||
{
|
||||
if(left.info.IsInmappingSlot)
|
||||
{
|
||||
(left, right) = (right, left);
|
||||
}
|
||||
left.Linkable(right);
|
||||
// left一定是输出端
|
||||
if (left.info.targetSlots.Contains(right) == false)
|
||||
{
|
||||
UnlinkAll(right);
|
||||
|
||||
left.info.targetSlots.Add(right);
|
||||
left.info.targetSlotName = right.info.slotName;
|
||||
left.info.targetNodes.Add(right.info.parentNode);
|
||||
left.info.targetNodeID = WorkflowManager.instance.GetGraphNodeID(right.info.parentNode);
|
||||
|
||||
right.info.targetSlots.Clear();
|
||||
right.info.targetSlots.Add(left);
|
||||
right.info.targetNodes.Clear();
|
||||
right.info.targetNodes.Add(left.info.parentNode);
|
||||
right.info.targetNodeID = WorkflowManager.instance.GetGraphNodeID(left.info.parentNode);
|
||||
right.info.targetSlotName = left.info.slotName;
|
||||
|
||||
left.SetDirty();
|
||||
right.SetDirty();
|
||||
}
|
||||
}
|
||||
public static void Unlink([In] NodeSlot slot, NodeSlot targetSlot)
|
||||
{
|
||||
int index = slot.info.targetSlots.IndexOf(targetSlot);
|
||||
if (index != -1)
|
||||
Unlink(slot, index);
|
||||
}
|
||||
public static void Unlink([In] NodeSlot slot, int slotIndex)
|
||||
{
|
||||
var targetSlot = slot.info.targetSlots[slotIndex];
|
||||
slot.info.targetSlots.RemoveAt(slotIndex);
|
||||
slot.info.targetNodes.RemoveAt(slotIndex);
|
||||
if (slot.info.targetSlots.Count == 0)
|
||||
{
|
||||
slot.info.targetNodeID = -1;
|
||||
slot.info.targetSlotName = "";
|
||||
}
|
||||
int r_slotIndex = targetSlot.info.targetSlots.IndexOf(slot);
|
||||
if (targetSlot != null && r_slotIndex != -1)
|
||||
{
|
||||
targetSlot.info.targetSlots.RemoveAt(r_slotIndex);
|
||||
targetSlot.info.targetNodes.RemoveAt(r_slotIndex);
|
||||
if (targetSlot.info.targetSlots.Count == 0)
|
||||
{
|
||||
targetSlot.info.targetNodeID = -1;
|
||||
targetSlot.info.targetSlotName = "";
|
||||
}
|
||||
targetSlot.SetDirty();
|
||||
}
|
||||
slot.SetDirty();
|
||||
}
|
||||
public static void UnlinkAll([In] NodeSlot slot)
|
||||
{
|
||||
foreach (var otherSlot in slot.info.targetSlots)
|
||||
{
|
||||
int index = otherSlot.info.targetSlots.IndexOf(slot);
|
||||
otherSlot.info.targetSlots.RemoveAt(index);
|
||||
otherSlot.info.targetNodes.RemoveAt(index);
|
||||
if (otherSlot.info.targetSlots.Count == 0)
|
||||
{
|
||||
otherSlot.info.targetNodeID = -1;
|
||||
otherSlot.info.targetSlotName = "";
|
||||
}
|
||||
otherSlot.SetDirty();
|
||||
}
|
||||
slot.info.targetSlots.Clear();
|
||||
slot.info.targetNodes.Clear();
|
||||
slot.info.targetNodeID = -1;
|
||||
slot.info.targetSlotName = "";
|
||||
slot.SetDirty();
|
||||
}
|
||||
public bool LinkTo([In, Opt] NodeSlot slot)
|
||||
{
|
||||
if (slot != null)
|
||||
{
|
||||
Link(this, slot);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static NodeSlot CurrentHighLightSlot { get; private set; }
|
||||
public static INodeSlotLinkable CurrentLinkTarget;
|
||||
public static void EnableHighLight(NodeSlot slot)
|
||||
{
|
||||
if (CurrentHighLightSlot != null)
|
||||
{
|
||||
CurrentHighLightSlot.HighLight.SetActive(false);
|
||||
}
|
||||
CurrentHighLightSlot = slot;
|
||||
CurrentHighLightSlot.HighLight.SetActive(true);
|
||||
CurrentLinkTarget = slot;
|
||||
}
|
||||
public static void DisableAllHighLight()
|
||||
{
|
||||
if (CurrentHighLightSlot != null)
|
||||
{
|
||||
CurrentHighLightSlot.HighLight.SetActive(false);
|
||||
CurrentHighLightSlot = null;
|
||||
}
|
||||
}
|
||||
public static void DisableHighLight(NodeSlot slot)
|
||||
{
|
||||
if (CurrentHighLightSlot == slot)
|
||||
{
|
||||
CurrentHighLightSlot.HighLight.SetActive(false);
|
||||
CurrentHighLightSlot = null;
|
||||
CurrentLinkTarget = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly Vector3[] zeroVecs = new Vector3[0];
|
||||
public Vector3[] GetCurrentLinkingVectors()
|
||||
{
|
||||
if (this.info == null)
|
||||
return zeroVecs;
|
||||
if (info.targetSlots.Count > 0 && info.IsInmappingSlot)
|
||||
{
|
||||
Vector3 position = this.Anchor.position;
|
||||
Vector3 localPosition = this.Anchor.localPosition;
|
||||
Vector3 targetPosition = info.targetSlots[0].Anchor.position;
|
||||
float offset = Mathf.Clamp((targetPosition - position).magnitude * ScaleFactor, 0, 30);
|
||||
return new Vector3[]{
|
||||
localPosition,
|
||||
localPosition+Vector3.left*offset,
|
||||
(targetPosition-position)*ScaleFactor+ localPosition+Vector3.right*offset,
|
||||
(targetPosition-position)*ScaleFactor+ localPosition
|
||||
};
|
||||
}
|
||||
else return zeroVecs;
|
||||
}
|
||||
|
||||
[Content, OnlyPlayMode, Ignore] private NodeSlotInfo m_info;
|
||||
public NodeSlotInfo info { get => m_info; private set => m_info = value; }
|
||||
public void SetupFromInfo(NodeSlotInfo value)
|
||||
{
|
||||
if (info != value)
|
||||
{
|
||||
info = value;
|
||||
info.slot = this;
|
||||
SetDirty();
|
||||
}
|
||||
}
|
||||
[Resources, OnlyNotNullMode, SerializeField] private Text Title;
|
||||
[Resources, OnlyNotNullMode, SerializeField] private LineRenderer LineRenderer;
|
||||
[Resources, OnlyNotNullMode, SerializeField] private Transform Anchor;
|
||||
[Resources, OnlyNotNullMode, SerializeField] private GameObject HighLight;
|
||||
[Setting] public float Offset = 1;
|
||||
[Content, SerializeField] private Vector3[] Points = new Vector3[0];
|
||||
|
||||
public string title { get => ((ITitle)this.Title).title; set => ((ITitle)this.Title).title = value; }
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
UnlinkAll(this);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
BehaviourContextManager contextManager = this.GetOrAddComponent<BehaviourContextManager>();
|
||||
contextManager.OnBeginDragEvent = BehaviourContextManager.InitializeContextSingleEvent(contextManager.OnBeginDragEvent, BeginDragLine);
|
||||
contextManager.OnDragEvent = BehaviourContextManager.InitializeContextSingleEvent(contextManager.OnDragEvent, DragLine);
|
||||
contextManager.OnEndDragEvent = BehaviourContextManager.InitializeContextSingleEvent(contextManager.OnEndDragEvent, EndDragLine);
|
||||
contextManager.OnPointerEnterEvent = BehaviourContextManager.InitializeContextSingleEvent(contextManager.OnPointerEnterEvent, _ =>
|
||||
{
|
||||
if (
|
||||
CurrentHighLightSlot == null ||
|
||||
(CurrentHighLightSlot.info.IsInmappingSlot != this.info.IsInmappingSlot &&
|
||||
CurrentHighLightSlot.info.typeIndicator == this.info.typeIndicator)
|
||||
)
|
||||
EnableHighLight(this);
|
||||
});
|
||||
contextManager.OnPointerExitEvent = BehaviourContextManager.InitializeContextSingleEvent(contextManager.OnPointerExitEvent, _ =>
|
||||
{
|
||||
DisableHighLight(this);
|
||||
});
|
||||
}
|
||||
|
||||
[Content, Ignore, SerializeField] private bool IsKeepDrag = false;
|
||||
[Content, Ignore, SerializeField] private bool IsDirty = false;
|
||||
private void Update()
|
||||
{
|
||||
if (IsKeepDrag == false && IsDirty)
|
||||
{
|
||||
Points = GetCurrentLinkingVectors();
|
||||
UpdateLineImmediate();
|
||||
}
|
||||
else if (IsDirty)
|
||||
{
|
||||
RebuildLine();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDirty()
|
||||
{
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void RebuildLine()
|
||||
{
|
||||
LineRenderer.positionCount = Points.Length;
|
||||
LineRenderer.SetPositions(Points);
|
||||
}
|
||||
|
||||
public void UpdateLineImmediate()
|
||||
{
|
||||
RebuildLine();
|
||||
title = $"{WorkflowManager.Transformer(info.slotName)}({WorkflowManager.Transformer(info.typeIndicator)})";
|
||||
IsDirty = false;
|
||||
}
|
||||
|
||||
public void BeginDragLine(PointerEventData _)
|
||||
{
|
||||
if (this.info.IsInmappingSlot)
|
||||
UnlinkAll(this);
|
||||
IsKeepDrag = true;
|
||||
SetDirty();
|
||||
}
|
||||
public void DragLine(PointerEventData pointer)
|
||||
{
|
||||
Points = new Vector3[] { Anchor.localPosition, (pointer.pointerCurrentRaycast.worldPosition - Anchor.position) * ScaleFactor + Anchor.localPosition };
|
||||
SetDirty();
|
||||
}
|
||||
public void EndDragLine(PointerEventData _)
|
||||
{
|
||||
IsKeepDrag = false;
|
||||
if (CurrentHighLightSlot != null && CurrentHighLightSlot.info.IsInmappingSlot != this.info.IsInmappingSlot)
|
||||
{
|
||||
Link(this, CurrentHighLightSlot);
|
||||
}
|
||||
SetDirty();
|
||||
DisableAllHighLight();
|
||||
}
|
||||
}
|
||||
}
|
11
Convention/[Visual]/Workflow/NodeSlot.cs.meta
Normal file
11
Convention/[Visual]/Workflow/NodeSlot.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fd0126d735f2225428b21f2121ecc526
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Convention/[Visual]/Workflow/Nodes.meta
Normal file
8
Convention/[Visual]/Workflow/Nodes.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d26371adfa7e4db47bd11b8cbf4f9307
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Convention/[Visual]/Workflow/Nodes/DisplayerNode.cs
Normal file
8
Convention/[Visual]/Workflow/Nodes/DisplayerNode.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Convention.Workflow
|
||||
{
|
||||
|
||||
}
|
11
Convention/[Visual]/Workflow/Nodes/DisplayerNode.cs.meta
Normal file
11
Convention/[Visual]/Workflow/Nodes/DisplayerNode.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 05e37045826234d469d8aa11593c65f6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
162
Convention/[Visual]/Workflow/Nodes/EndNode.cs
Normal file
162
Convention/[Visual]/Workflow/Nodes/EndNode.cs
Normal file
@@ -0,0 +1,162 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Convention.WindowsUI;
|
||||
using Convention.WindowsUI.Variant;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace Convention.Workflow
|
||||
{
|
||||
[Serializable, ArgPackage]
|
||||
public class EndNodeInfo : NodeInfo
|
||||
{
|
||||
protected override NodeInfo CreateTemplate()
|
||||
{
|
||||
return new EndNodeInfo();
|
||||
}
|
||||
}
|
||||
|
||||
public class EndNode : Node, INodeSlotLinkable
|
||||
{
|
||||
internal static List<EndNode> AllEndNodes = new();
|
||||
|
||||
// ContextBehaviour
|
||||
|
||||
public object end_result;
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
end_result = null;
|
||||
AllEndNodes.Add(this);
|
||||
var context = gameObject.GetOrAddComponent<BehaviourContextManager>();
|
||||
context.OnPointerClickEvent = BehaviourContextManager.InitializeContextSingleEvent(context.OnPointerClickEvent, PointerRightClickAndOpenMenu);
|
||||
}
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
AllEndNodes.Remove(this);
|
||||
}
|
||||
|
||||
private Dictionary<string, PropertiesWindow.ItemEntry> m_dynamicSlots = new();
|
||||
|
||||
public override void PointerRightClickAndOpenMenu(PointerEventData pointer)
|
||||
{
|
||||
if (pointer.button == PointerEventData.InputButton.Right)
|
||||
{
|
||||
List<SharedModule.CallbackData> callbacks = new()
|
||||
{
|
||||
new (WorkflowManager.Transformer("Create New Slot"), x =>
|
||||
{
|
||||
SharedModule.instance.SingleEditString(
|
||||
WorkflowManager.Transformer("SlotName"),
|
||||
WorkflowManager.Transformer("SlotName"),
|
||||
y => AddSlot(y,"string"));
|
||||
}),
|
||||
new (WorkflowManager.Transformer("Delete"), x =>
|
||||
{
|
||||
WorkflowManager.instance.DestroyNode(this);
|
||||
})
|
||||
};
|
||||
SharedModule.instance.OpenCustomMenu(WorkflowManager.instance.UIFocusObject, callbacks.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
public bool AddSlot(string name, string typeIndicator)
|
||||
{
|
||||
if (this.m_Inmapping.ContainsKey(name))
|
||||
return false;
|
||||
var entry = CreateGraphNodeInSlots(1)[0];
|
||||
RectTransform curEntryRect = entry.ref_value.transform as RectTransform;
|
||||
this.m_Inmapping[name] = entry.ref_value.GetComponent<NodeSlot>();
|
||||
this.m_Inmapping[name].SetupFromInfo(new NodeSlotInfo()
|
||||
{
|
||||
parentNode = this,
|
||||
slotName = name,
|
||||
typeIndicator = typeIndicator,
|
||||
IsInmappingSlot = true
|
||||
});
|
||||
m_dynamicSlots.Add(name, entry);
|
||||
this.rectTransform.sizeDelta = new Vector2(this.rectTransform.sizeDelta.x, this.rectTransform.sizeDelta.y + curEntryRect.rect.height);
|
||||
ConventionUtility.CreateSteps().Wait(1f, () =>
|
||||
{
|
||||
foreach (var (key, slot) in this.m_Inmapping)
|
||||
{
|
||||
slot.SetDirty();
|
||||
}
|
||||
}).Invoke();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool RemoveSlot(string name)
|
||||
{
|
||||
if (this.m_Inmapping.ContainsKey(name) == false)
|
||||
return false;
|
||||
this.m_Inmapping.Remove(name);
|
||||
RectTransform curEntryRect = m_dynamicSlots[name].ref_value.transform as RectTransform;
|
||||
this.rectTransform.sizeDelta = new Vector2(this.rectTransform.sizeDelta.x, this.rectTransform.sizeDelta.y - curEntryRect.rect.height);
|
||||
m_dynamicSlots[name].Release();
|
||||
m_dynamicSlots.Remove(name);
|
||||
ConventionUtility.CreateSteps().Next(() =>
|
||||
{
|
||||
foreach (var (key, slot) in this.m_Inmapping)
|
||||
{
|
||||
slot.SetDirty();
|
||||
}
|
||||
}).Invoke();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool LinkTo([In, Opt] NodeSlot other)
|
||||
{
|
||||
if (Linkable(other))
|
||||
{
|
||||
AddSlot(other.info.slotName, other.info.typeIndicator);
|
||||
var slot = m_dynamicSlots[other.info.slotName].ref_value.GetComponent<NodeSlot>();
|
||||
if (slot.Linkable(other))
|
||||
{
|
||||
slot.LinkTo(other);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Linkable([In] NodeSlot other)
|
||||
{
|
||||
return other != null && other.info.IsInmappingSlot == false;
|
||||
}
|
||||
|
||||
[return: ReturnMayNull]
|
||||
public GameObject GetExtensionModule(string slotName)
|
||||
{
|
||||
if (this.m_Inmapping.ContainsKey(slotName))
|
||||
{
|
||||
return this.m_Inmapping[slotName].ExtensionModule;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
[return: ReturnMayNull]
|
||||
public T GetExtensionModule<T>(string slotName) where T : Component
|
||||
{
|
||||
if (this.m_Inmapping.ContainsKey(slotName))
|
||||
{
|
||||
var go = this.m_Inmapping[slotName].ExtensionModule;
|
||||
if (go != null)
|
||||
{
|
||||
return ConventionUtility.SeekComponent<T>(go);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public List<string> GetAllInslotNames()
|
||||
{
|
||||
return m_Inmapping.Keys.ToList();
|
||||
}
|
||||
public bool ContainsInslot(string slotName)
|
||||
{
|
||||
return m_Inmapping.ContainsKey(slotName);
|
||||
}
|
||||
}
|
||||
}
|
11
Convention/[Visual]/Workflow/Nodes/EndNode.cs.meta
Normal file
11
Convention/[Visual]/Workflow/Nodes/EndNode.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 227064b71f46ce54aba01ed5a07a6da9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Convention/[Visual]/Workflow/Nodes/StartNodes.meta
Normal file
8
Convention/[Visual]/Workflow/Nodes/StartNodes.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d6e06d4260762a44e9e66ca0669eedc1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Convention.WindowsUI;
|
||||
using Convention.WindowsUI.Variant;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Convention.Workflow
|
||||
{
|
||||
[Serializable, ArgPackage]
|
||||
public class ResourceNodeInfo : StartNodeInfo
|
||||
{
|
||||
[NonSerialized] private string l_resource = WorkflowManager.Transformer(nameof(resource));
|
||||
[InspectorDraw(InspectorDrawType.Text, true, true, nameGenerater: nameof(l_resource))]
|
||||
public string resource = "unknown";
|
||||
|
||||
public ResourceNodeInfo() : this("") { }
|
||||
public ResourceNodeInfo(string resource, string outmappingName = "value")
|
||||
{
|
||||
this.resource = resource;
|
||||
this.outmapping = new()
|
||||
{
|
||||
{
|
||||
outmappingName, new NodeSlotInfo()
|
||||
{
|
||||
slotName = outmappingName,
|
||||
typeIndicator = "string",
|
||||
IsInmappingSlot = false,
|
||||
}
|
||||
}
|
||||
};
|
||||
this.inmapping = new();
|
||||
this.title = "Resource";
|
||||
}
|
||||
protected override NodeInfo CreateTemplate()
|
||||
{
|
||||
return new ResourceNodeInfo();
|
||||
}
|
||||
protected override void CloneValues([In] NodeInfo clonen)
|
||||
{
|
||||
((ResourceNodeInfo)clonen).resource = this.resource;
|
||||
base.CloneValues(clonen);
|
||||
}
|
||||
}
|
||||
|
||||
public class ResourceNode : StartNode, IText
|
||||
{
|
||||
[Resources, OnlyNotNullMode] public ModernUIInputField InputField;
|
||||
[Content, OnlyPlayMode] public bool isEditing = false;
|
||||
|
||||
public ResourceNodeInfo MyResourceNodeInfo => this.info as ResourceNodeInfo;
|
||||
|
||||
public string text { get => ((IText)this.InputField).text; set => ((IText)this.InputField).text = value; }
|
||||
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
InputField.InputFieldSource.Source.onSelect.AddListener(_ => isEditing = true);
|
||||
InputField.InputFieldSource.Source.onEndEdit.AddListener(str =>
|
||||
{
|
||||
MyResourceNodeInfo.resource = str;
|
||||
isEditing = false;
|
||||
});
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (info != null && this.isEditing == false && RectTransformExtension.IsVisible(this.rectTransform))
|
||||
{
|
||||
this.text = this.MyResourceNodeInfo.resource;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 24bfe76a1dd2f914c8222f30cf7e61b0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Convention.WindowsUI;
|
||||
using Convention.WindowsUI.Variant;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Convention.Workflow
|
||||
{
|
||||
public class SelectorNodeInfo : StartNodeInfo
|
||||
{
|
||||
public virtual IEnumerable<string> EnumNamesGenerater()
|
||||
{
|
||||
return new List<string>()
|
||||
{
|
||||
WorkflowManager.Transformer("unknown")
|
||||
};
|
||||
}
|
||||
|
||||
[NonSerialized] private string l_select = WorkflowManager.Transformer(nameof(select));
|
||||
[InspectorDraw(InspectorDrawType.Enum, true, false, nameGenerater: nameof(l_select), enumGenerater: nameof(EnumNamesGenerater))]
|
||||
public string select = "";
|
||||
|
||||
public SelectorNodeInfo() : this("") { }
|
||||
public SelectorNodeInfo(string select, string outputName = "select")
|
||||
{
|
||||
this.select = select;
|
||||
this.outmapping = new()
|
||||
{
|
||||
{
|
||||
outputName, new NodeSlotInfo()
|
||||
{
|
||||
slotName = outputName,
|
||||
typeIndicator="string",
|
||||
IsInmappingSlot=false
|
||||
}
|
||||
}
|
||||
};
|
||||
this.inmapping = new();
|
||||
this.title = "Selector";
|
||||
}
|
||||
|
||||
protected override NodeInfo CreateTemplate()
|
||||
{
|
||||
return new SelectorNodeInfo();
|
||||
}
|
||||
protected override void CloneValues([In] NodeInfo clonen)
|
||||
{
|
||||
var info = (SelectorNodeInfo)clonen;
|
||||
info.select = select;
|
||||
info.outmapping = new(outmapping);
|
||||
base.CloneValues(clonen);
|
||||
}
|
||||
}
|
||||
|
||||
public class SelectorNode : StartNode
|
||||
{
|
||||
[Resources, OnlyNotNullMode,SerializeField] private ModernUIDropdown DropDown;
|
||||
|
||||
public SelectorNodeInfo MySelectorInfo => info as SelectorNodeInfo;
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
DropDown.AddListener(x => MySelectorInfo.select = x);
|
||||
}
|
||||
|
||||
protected virtual void RebuildDropDown(ModernUIDropdown dropdown, SelectorNodeInfo info)
|
||||
{
|
||||
foreach (var name in info.EnumNamesGenerater())
|
||||
{
|
||||
dropdown.CreateOption(name);
|
||||
}
|
||||
dropdown.RefreshImmediate();
|
||||
if (string.IsNullOrEmpty(info.select) == false)
|
||||
dropdown.Select(info.select);
|
||||
}
|
||||
|
||||
protected override void WhenSetup(NodeInfo info)
|
||||
{
|
||||
RebuildDropDown(DropDown, info as SelectorNodeInfo);
|
||||
base.WhenSetup(info);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f9707e651688bd4f89ece4047a68b95
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
73
Convention/[Visual]/Workflow/Nodes/StartNodes/TextNode.cs
Normal file
73
Convention/[Visual]/Workflow/Nodes/StartNodes/TextNode.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System.Linq;
|
||||
using Convention.WindowsUI;
|
||||
using Convention.WindowsUI.Variant;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Convention.Workflow
|
||||
{
|
||||
public class TextNodeInfo : StartNodeInfo
|
||||
{
|
||||
private string l_text => WorkflowManager.Transformer(nameof(text));
|
||||
[InspectorDraw(InspectorDrawType.Text, nameGenerater: nameof(l_text))]
|
||||
public string text;
|
||||
|
||||
public TextNodeInfo() : this("") { }
|
||||
public TextNodeInfo(string text, string outmappingName = "text")
|
||||
{
|
||||
this.text = text;
|
||||
this.outmapping = new()
|
||||
{
|
||||
{
|
||||
outmappingName, new NodeSlotInfo()
|
||||
{
|
||||
slotName = outmappingName,
|
||||
typeIndicator = "string",
|
||||
IsInmappingSlot = false,
|
||||
}
|
||||
}
|
||||
};
|
||||
this.inmapping = new();
|
||||
this.title = "Text";
|
||||
}
|
||||
|
||||
protected override NodeInfo CreateTemplate()
|
||||
{
|
||||
return new TextNodeInfo();
|
||||
}
|
||||
protected override void CloneValues([In] NodeInfo clonen)
|
||||
{
|
||||
((TextNodeInfo)clonen).text = text;
|
||||
base.CloneValues(clonen);
|
||||
}
|
||||
}
|
||||
|
||||
public class TextNode : StartNode, IText
|
||||
{
|
||||
[Resources, OnlyNotNullMode] public ModernUIInputField InputField;
|
||||
[Content, OnlyPlayMode] public bool isEditing = false;
|
||||
|
||||
public TextNodeInfo MyTextNodeInfo => this.info as TextNodeInfo;
|
||||
|
||||
public string text { get => ((IText)this.InputField).text; set => ((IText)this.InputField).text = value; }
|
||||
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
InputField.InputFieldSource.Source.onSelect.AddListener(_ => isEditing = true);
|
||||
InputField.InputFieldSource.Source.onEndEdit.AddListener(str =>
|
||||
{
|
||||
MyTextNodeInfo.text = str;
|
||||
isEditing = false;
|
||||
});
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (info != null && this.isEditing == false && RectTransformExtension.IsVisible(this.rectTransform))
|
||||
{
|
||||
this.text = this.MyTextNodeInfo.text;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eaab2d787a0d66642a89d8b957606de5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
96
Convention/[Visual]/Workflow/Nodes/StartNodes/ValueNode.cs
Normal file
96
Convention/[Visual]/Workflow/Nodes/StartNodes/ValueNode.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Convention.WindowsUI;
|
||||
using Convention.WindowsUI.Variant;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Convention.Workflow
|
||||
{
|
||||
public class ValueNodeInfo : StartNodeInfo
|
||||
{
|
||||
[NonSerialized] private string l_value = WorkflowManager.Transformer(nameof(value));
|
||||
[InspectorDraw(InspectorDrawType.Text, true, true, nameGenerater: nameof(l_value))]
|
||||
public float value = 0;
|
||||
[NonSerialized] private string l_min = WorkflowManager.Transformer(nameof(min));
|
||||
[InspectorDraw(InspectorDrawType.Auto, true, true, nameGenerater: nameof(l_min))]
|
||||
public float min = 0;
|
||||
[NonSerialized]private string l_max = WorkflowManager.Transformer(nameof(max));
|
||||
[InspectorDraw(InspectorDrawType.Auto, true, true, nameGenerater: nameof(l_max))]
|
||||
public float max = 1;
|
||||
|
||||
public ValueNodeInfo() : this(0) { }
|
||||
public ValueNodeInfo(float value, string outmappingName = "value")
|
||||
{
|
||||
this.value = value;
|
||||
this.outmapping = new()
|
||||
{
|
||||
{
|
||||
outmappingName, new NodeSlotInfo()
|
||||
{
|
||||
slotName = outmappingName,
|
||||
typeIndicator = "float",
|
||||
IsInmappingSlot = false,
|
||||
}
|
||||
}
|
||||
};
|
||||
this.inmapping = new();
|
||||
this.title = "Value";
|
||||
}
|
||||
|
||||
protected override NodeInfo CreateTemplate()
|
||||
{
|
||||
return new ValueNodeInfo();
|
||||
}
|
||||
protected override void CloneValues([In] NodeInfo clonen)
|
||||
{
|
||||
var info = ((ValueNodeInfo)clonen);
|
||||
info.value = value;
|
||||
info.min = min;
|
||||
info.max = max;
|
||||
base.CloneValues(clonen);
|
||||
}
|
||||
}
|
||||
|
||||
public class ValueNode : StartNode, IText
|
||||
{
|
||||
[Resources, OnlyNotNullMode] public ModernUIInputField InputField;
|
||||
[Resources, OnlyNotNullMode] public ModernUIFillBar RangeBar;
|
||||
[Content, OnlyPlayMode] public bool isEditing = false;
|
||||
|
||||
public ValueNodeInfo MyValueNodeInfo => this.info as ValueNodeInfo;
|
||||
|
||||
public string text { get => ((IText)this.InputField).text; set => ((IText)this.InputField).text = value; }
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
InputField.InputFieldSource.Source.onSelect.AddListener(_ => isEditing = true);
|
||||
InputField.InputFieldSource.Source.onEndEdit.AddListener(str =>
|
||||
{
|
||||
if (float.TryParse(str, out float value))
|
||||
MyValueNodeInfo.value = value;
|
||||
else
|
||||
MyValueNodeInfo.value = 0;
|
||||
isEditing = false;
|
||||
});
|
||||
}
|
||||
|
||||
protected override void WhenSetup(NodeInfo info)
|
||||
{
|
||||
base.WhenSetup(info);
|
||||
RangeBar.minValue = MyValueNodeInfo.min;
|
||||
RangeBar.maxValue = MyValueNodeInfo.max;
|
||||
RangeBar.SetValue(MyValueNodeInfo.value);
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (info != null && this.isEditing == false && RectTransformExtension.IsVisible(this.rectTransform))
|
||||
{
|
||||
RangeBar.minValue = MyValueNodeInfo.min;
|
||||
RangeBar.maxValue = MyValueNodeInfo.max;
|
||||
RangeBar.SetValue(MyValueNodeInfo.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8404795928101e843ad4d836cea5c1f1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
332
Convention/[Visual]/Workflow/OnEntryRunWorkflow.anim
Normal file
332
Convention/[Visual]/Workflow/OnEntryRunWorkflow.anim
Normal file
@@ -0,0 +1,332 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!74 &7400000
|
||||
AnimationClip:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: OnEntryRunWorkflow
|
||||
serializedVersion: 7
|
||||
m_Legacy: 0
|
||||
m_Compressed: 0
|
||||
m_UseHighQualityCurve: 1
|
||||
m_RotationCurves: []
|
||||
m_CompressedRotationCurves: []
|
||||
m_EulerCurves: []
|
||||
m_PositionCurves: []
|
||||
m_ScaleCurves: []
|
||||
m_FloatCurves:
|
||||
- serializedVersion: 2
|
||||
curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 0
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 0.083333336
|
||||
value: 0.5
|
||||
inSlope: 3.6
|
||||
outSlope: 3.6
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 0.25
|
||||
value: 0.9
|
||||
inSlope: 0.43636376
|
||||
outSlope: 0.43636376
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 1
|
||||
value: 1
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_Alpha
|
||||
path: UI Canvas/AnimationPlane
|
||||
classID: 225
|
||||
script: {fileID: 0}
|
||||
flags: 0
|
||||
- serializedVersion: 2
|
||||
curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 0
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 0.25
|
||||
value: 0
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 0.41666666
|
||||
value: 100
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_SizeDelta.y
|
||||
path: UI Canvas/AnimationPlane/Shadow/Image
|
||||
classID: 224
|
||||
script: {fileID: 0}
|
||||
flags: 0
|
||||
- serializedVersion: 2
|
||||
curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 0
|
||||
inSlope: Infinity
|
||||
outSlope: Infinity
|
||||
tangentMode: 103
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
- serializedVersion: 3
|
||||
time: 0.016666668
|
||||
value: 1
|
||||
inSlope: Infinity
|
||||
outSlope: Infinity
|
||||
tangentMode: 103
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
- serializedVersion: 3
|
||||
time: 1
|
||||
value: 1
|
||||
inSlope: Infinity
|
||||
outSlope: Infinity
|
||||
tangentMode: 103
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_BlocksRaycasts
|
||||
path: UI Canvas/AnimationPlane
|
||||
classID: 225
|
||||
script: {fileID: 0}
|
||||
flags: 0
|
||||
m_PPtrCurves: []
|
||||
m_SampleRate: 60
|
||||
m_WrapMode: 0
|
||||
m_Bounds:
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
m_Extent: {x: 0, y: 0, z: 0}
|
||||
m_ClipBindingConstant:
|
||||
genericBindings:
|
||||
- serializedVersion: 2
|
||||
path: 4103470125
|
||||
attribute: 1574349066
|
||||
script: {fileID: 0}
|
||||
typeID: 225
|
||||
customType: 0
|
||||
isPPtrCurve: 0
|
||||
isIntCurve: 0
|
||||
isSerializeReferenceCurve: 0
|
||||
- serializedVersion: 2
|
||||
path: 355489497
|
||||
attribute: 38095219
|
||||
script: {fileID: 0}
|
||||
typeID: 224
|
||||
customType: 28
|
||||
isPPtrCurve: 0
|
||||
isIntCurve: 0
|
||||
isSerializeReferenceCurve: 0
|
||||
- serializedVersion: 2
|
||||
path: 4103470125
|
||||
attribute: 3739863151
|
||||
script: {fileID: 0}
|
||||
typeID: 225
|
||||
customType: 0
|
||||
isPPtrCurve: 0
|
||||
isIntCurve: 0
|
||||
isSerializeReferenceCurve: 0
|
||||
pptrCurveMapping: []
|
||||
m_AnimationClipSettings:
|
||||
serializedVersion: 2
|
||||
m_AdditiveReferencePoseClip: {fileID: 0}
|
||||
m_AdditiveReferencePoseTime: 0
|
||||
m_StartTime: 0
|
||||
m_StopTime: 1
|
||||
m_OrientationOffsetY: 0
|
||||
m_Level: 0
|
||||
m_CycleOffset: 0
|
||||
m_HasAdditiveReferencePose: 0
|
||||
m_LoopTime: 0
|
||||
m_LoopBlend: 0
|
||||
m_LoopBlendOrientation: 0
|
||||
m_LoopBlendPositionY: 0
|
||||
m_LoopBlendPositionXZ: 0
|
||||
m_KeepOriginalOrientation: 0
|
||||
m_KeepOriginalPositionY: 1
|
||||
m_KeepOriginalPositionXZ: 0
|
||||
m_HeightFromFeet: 0
|
||||
m_Mirror: 0
|
||||
m_EditorCurves:
|
||||
- serializedVersion: 2
|
||||
curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 0
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 0.083333336
|
||||
value: 0.5
|
||||
inSlope: 3.6
|
||||
outSlope: 3.6
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 0.25
|
||||
value: 0.9
|
||||
inSlope: 0.43636376
|
||||
outSlope: 0.43636376
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 1
|
||||
value: 1
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_Alpha
|
||||
path: UI Canvas/AnimationPlane
|
||||
classID: 225
|
||||
script: {fileID: 0}
|
||||
flags: 0
|
||||
- serializedVersion: 2
|
||||
curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 0
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 0.25
|
||||
value: 0
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 0.41666666
|
||||
value: 100
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_SizeDelta.y
|
||||
path: UI Canvas/AnimationPlane/Shadow/Image
|
||||
classID: 224
|
||||
script: {fileID: 0}
|
||||
flags: 0
|
||||
- serializedVersion: 2
|
||||
curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 0
|
||||
inSlope: Infinity
|
||||
outSlope: Infinity
|
||||
tangentMode: 103
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
- serializedVersion: 3
|
||||
time: 0.016666668
|
||||
value: 1
|
||||
inSlope: Infinity
|
||||
outSlope: Infinity
|
||||
tangentMode: 103
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
- serializedVersion: 3
|
||||
time: 1
|
||||
value: 1
|
||||
inSlope: Infinity
|
||||
outSlope: Infinity
|
||||
tangentMode: 103
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_BlocksRaycasts
|
||||
path: UI Canvas/AnimationPlane
|
||||
classID: 225
|
||||
script: {fileID: 0}
|
||||
flags: 0
|
||||
m_EulerEditorCurves: []
|
||||
m_HasGenericRootTransform: 0
|
||||
m_HasMotionFloatCurves: 0
|
||||
m_Events: []
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cbeef9f55988bc645a8bcf751e8779f4
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
18
Convention/[Visual]/Workflow/StartNode.cs
Normal file
18
Convention/[Visual]/Workflow/StartNode.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
|
||||
namespace Convention.Workflow
|
||||
{
|
||||
[Serializable, ArgPackage]
|
||||
public class StartNodeInfo : NodeInfo
|
||||
{
|
||||
protected override NodeInfo CreateTemplate()
|
||||
{
|
||||
return new StartNodeInfo();
|
||||
}
|
||||
}
|
||||
|
||||
public class StartNode : Node
|
||||
{
|
||||
|
||||
}
|
||||
}
|
11
Convention/[Visual]/Workflow/StartNode.cs.meta
Normal file
11
Convention/[Visual]/Workflow/StartNode.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ea9e2ae1ef3fbf441aaf9fe79a3639c3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
134
Convention/[Visual]/Workflow/StepNode.cs
Normal file
134
Convention/[Visual]/Workflow/StepNode.cs
Normal file
@@ -0,0 +1,134 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Convention.WindowsUI;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Convention.Workflow
|
||||
{
|
||||
[Serializable, ArgPackage]
|
||||
public class StepNodeInfo : NodeInfo
|
||||
{
|
||||
public string module = "global";
|
||||
public string funcname = "";
|
||||
protected override NodeInfo CreateTemplate()
|
||||
{
|
||||
return new StepNodeInfo();
|
||||
}
|
||||
protected override void CloneValues([In] NodeInfo clonen)
|
||||
{
|
||||
var info = (StepNodeInfo)clonen;
|
||||
info.module = module;
|
||||
info.funcname = funcname;
|
||||
base.CloneValues(clonen);
|
||||
}
|
||||
}
|
||||
|
||||
public class StepNode : Node
|
||||
{
|
||||
[Resources, OnlyNotNullMode] public ModernUIDropdown FunctionSelector;
|
||||
|
||||
public StepNodeInfo MyStepInfo => info as StepNodeInfo;
|
||||
|
||||
private void ClearSelector()
|
||||
{
|
||||
FunctionSelector.ClearOptions();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (WorkflowManager.instance == null)
|
||||
return;
|
||||
ClearSelector();
|
||||
var names = WorkflowManager.instance.GetAllModuleName();
|
||||
if (names.Count > 0)
|
||||
{
|
||||
SelectModel(names);
|
||||
}
|
||||
else
|
||||
{
|
||||
FunctionSelector.CreateOption(WorkflowManager.Transformer("No Module Registered"));
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectModel(List<string> names)
|
||||
{
|
||||
foreach (var moduleName in names)
|
||||
{
|
||||
this.FunctionSelector.CreateOption(WorkflowManager.Transformer(moduleName)).toggleEvents.AddListener(x =>
|
||||
{
|
||||
if (x)
|
||||
{
|
||||
ClearSelector();
|
||||
SelectFunctionModel(moduleName);
|
||||
}
|
||||
});
|
||||
}
|
||||
this.FunctionSelector.RefreshImmediate();
|
||||
}
|
||||
|
||||
private void SelectFunctionModel(string moduleName)
|
||||
{
|
||||
foreach (var funcModel in WorkflowManager.instance.GetAllFunctionModel(moduleName))
|
||||
{
|
||||
this.FunctionSelector.CreateOption(WorkflowManager.Transformer(funcModel.name)).toggleEvents.AddListener(y =>
|
||||
{
|
||||
if (y)
|
||||
{
|
||||
SetupWhenFunctionNameCatch(funcModel);
|
||||
}
|
||||
});
|
||||
}
|
||||
this.FunctionSelector.RefreshImmediate();
|
||||
}
|
||||
|
||||
public void SetupWhenFunctionNameCatch(FunctionModel funcModel)
|
||||
{
|
||||
var oriExtensionHeight = this.ExtensionHeight;
|
||||
this.ExtensionHeight = 0;
|
||||
this.MyStepInfo.module = funcModel.module;
|
||||
this.MyStepInfo.funcname = funcModel.name;
|
||||
this.MyStepInfo.inmapping = new();
|
||||
if (this.MyStepInfo.title == this.MyStepInfo.GetType().Name[..^4])
|
||||
this.MyStepInfo.title = funcModel.name;
|
||||
foreach (var (name, type) in funcModel.parameters)
|
||||
{
|
||||
this.MyStepInfo.inmapping[name] = new NodeSlotInfo()
|
||||
{
|
||||
slotName = name,
|
||||
typeIndicator = type,
|
||||
IsInmappingSlot = true
|
||||
};
|
||||
}
|
||||
this.MyStepInfo.outmapping = new();
|
||||
foreach (var (name, type) in funcModel.returns)
|
||||
{
|
||||
this.MyStepInfo.outmapping[name] = new NodeSlotInfo()
|
||||
{
|
||||
slotName = name,
|
||||
typeIndicator = type,
|
||||
IsInmappingSlot = false
|
||||
};
|
||||
}
|
||||
this.FunctionSelector.gameObject.SetActive(false);
|
||||
this.ExtensionHeight = 0;
|
||||
this.ClearLink();
|
||||
this.ClearSlots();
|
||||
this.BuildSlots();
|
||||
this.BuildLink();
|
||||
this.InoutContainerPlane.rectTransform.sizeDelta = new Vector2(
|
||||
this.InoutContainerPlane.rectTransform.sizeDelta.x,
|
||||
this.InoutContainerPlane.rectTransform.sizeDelta.y + oriExtensionHeight
|
||||
);
|
||||
this.RefreshRectTransform();
|
||||
}
|
||||
|
||||
protected override void WhenSetup(NodeInfo info)
|
||||
{
|
||||
base.WhenSetup(info);
|
||||
if (string.IsNullOrEmpty(MyStepInfo.funcname) == false)
|
||||
{
|
||||
SetupWhenFunctionNameCatch(WorkflowManager.instance.GetFunctionModel(MyStepInfo.module, MyStepInfo.funcname));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Convention/[Visual]/Workflow/StepNode.cs.meta
Normal file
11
Convention/[Visual]/Workflow/StepNode.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3c3a9d5b6db27ae4bb28554ecc681b6f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
130
Convention/[Visual]/Workflow/WorkflowGraph.controller
Normal file
130
Convention/[Visual]/Workflow/WorkflowGraph.controller
Normal file
@@ -0,0 +1,130 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1107 &-8138631149079467525
|
||||
AnimatorStateMachine:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Base Layer
|
||||
m_ChildStates:
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: -4332790445053841364}
|
||||
m_Position: {x: 400, y: 70, z: 0}
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: -2159031066727738487}
|
||||
m_Position: {x: 50, y: 170, z: 0}
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: -5526377917478383796}
|
||||
m_Position: {x: 400, y: 120, z: 0}
|
||||
m_ChildStateMachines: []
|
||||
m_AnyStateTransitions: []
|
||||
m_EntryTransitions: []
|
||||
m_StateMachineTransitions: {}
|
||||
m_StateMachineBehaviours: []
|
||||
m_AnyStatePosition: {x: 50, y: 60, z: 0}
|
||||
m_EntryPosition: {x: 50, y: 120, z: 0}
|
||||
m_ExitPosition: {x: 800, y: 120, z: 0}
|
||||
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
|
||||
m_DefaultState: {fileID: -2159031066727738487}
|
||||
--- !u!1102 &-5526377917478383796
|
||||
AnimatorState:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: OnQuitRunWorkflow
|
||||
m_Speed: -1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions: []
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
m_WriteDefaultValues: 1
|
||||
m_Mirror: 0
|
||||
m_SpeedParameterActive: 0
|
||||
m_MirrorParameterActive: 0
|
||||
m_CycleOffsetParameterActive: 0
|
||||
m_TimeParameterActive: 0
|
||||
m_Motion: {fileID: 7400000, guid: cbeef9f55988bc645a8bcf751e8779f4, type: 2}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
--- !u!1102 &-4332790445053841364
|
||||
AnimatorState:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: OnEntryRunWorkflow
|
||||
m_Speed: 1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions: []
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
m_WriteDefaultValues: 1
|
||||
m_Mirror: 0
|
||||
m_SpeedParameterActive: 0
|
||||
m_MirrorParameterActive: 0
|
||||
m_CycleOffsetParameterActive: 0
|
||||
m_TimeParameterActive: 0
|
||||
m_Motion: {fileID: 7400000, guid: cbeef9f55988bc645a8bcf751e8779f4, type: 2}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
--- !u!1102 &-2159031066727738487
|
||||
AnimatorState:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: New State
|
||||
m_Speed: 1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions: []
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
m_WriteDefaultValues: 1
|
||||
m_Mirror: 0
|
||||
m_SpeedParameterActive: 0
|
||||
m_MirrorParameterActive: 0
|
||||
m_CycleOffsetParameterActive: 0
|
||||
m_TimeParameterActive: 0
|
||||
m_Motion: {fileID: 0}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
--- !u!91 &9100000
|
||||
AnimatorController:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: WorkflowGraph
|
||||
serializedVersion: 5
|
||||
m_AnimatorParameters: []
|
||||
m_AnimatorLayers:
|
||||
- serializedVersion: 5
|
||||
m_Name: Base Layer
|
||||
m_StateMachine: {fileID: -8138631149079467525}
|
||||
m_Mask: {fileID: 0}
|
||||
m_Motions: []
|
||||
m_Behaviours: []
|
||||
m_BlendingMode: 0
|
||||
m_SyncedLayerIndex: -1
|
||||
m_DefaultWeight: 0
|
||||
m_IKPass: 0
|
||||
m_SyncedLayerAffectsTiming: 0
|
||||
m_Controller: {fileID: 9100000}
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4891df624d2e69241bb634ec11c36645
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 9100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
383
Convention/[Visual]/Workflow/WorkflowManager.cs
Normal file
383
Convention/[Visual]/Workflow/WorkflowManager.cs
Normal file
@@ -0,0 +1,383 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Convention.WindowsUI.Variant;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace Convention.Workflow
|
||||
{
|
||||
[Serializable, ArgPackage]
|
||||
public class NodeResult
|
||||
{
|
||||
public int nodeID;
|
||||
public string nodeTitle;
|
||||
public Dictionary<string, string> result;
|
||||
}
|
||||
|
||||
[Serializable, ArgPackage]
|
||||
public class ContextResult
|
||||
{
|
||||
public string hashID;
|
||||
public List<NodeResult> results;
|
||||
public float progress;
|
||||
public int task_count;
|
||||
public List<int> current_running_nodes;
|
||||
}
|
||||
|
||||
[Serializable, ArgPackage]
|
||||
public class FunctionModel
|
||||
{
|
||||
public string name = "unknown";
|
||||
public string description = "unknown";
|
||||
public Dictionary<string, string> parameters = new();
|
||||
public Dictionary<string, string> returns = new();
|
||||
public string module = "global";
|
||||
}
|
||||
|
||||
[Serializable, ArgPackage]
|
||||
public class Workflow
|
||||
{
|
||||
public List<NodeInfo> Datas = new();
|
||||
[NonSerialized] public List<Node> Nodes = new();
|
||||
public List<FunctionModel> Functions = new();
|
||||
}
|
||||
|
||||
public class WorkflowManager : MonoSingleton<WorkflowManager>
|
||||
{
|
||||
public static float CameraZ = 0;
|
||||
|
||||
[Content] public Workflow m_workflow;
|
||||
public Workflow workflow
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_workflow;
|
||||
}
|
||||
//set
|
||||
//{
|
||||
// if (m_workflow == value)
|
||||
// return;
|
||||
// ClearWorkflowGraph();
|
||||
// m_workflow = value;
|
||||
// BuildWorkflowGraph();
|
||||
//}
|
||||
}
|
||||
[Resources, OnlyNotNullMode, SerializeField] private Transform m_CameraTransform;
|
||||
[Setting] public float ScrollSpeed = 1;
|
||||
[Setting, OnlyNotNullMode] public ScriptableObject GraphNodePrefabs;
|
||||
[Setting, HopeNotNull] public ScriptableObject TextLabels;
|
||||
|
||||
//[Resources, SerializeField, OnlyNotNullMode, Header("Prefabs")]
|
||||
//private GameObject GraphNodePrefab;
|
||||
[Resources, SerializeField, OnlyNotNullMode, Header("Content")]
|
||||
public RectTransform ContentPlane;
|
||||
[Resources, SerializeField, OnlyNotNullMode, Header("Mouse Click")]
|
||||
public RectTransform focusObject;
|
||||
[SerializeField, OnlyNotNullMode]
|
||||
public RectTransform UIFocusObject;
|
||||
private List<SharedModule.CallbackData> callbackDatas = new();
|
||||
private HashSet<Type> registeredCallbackNodeType = new();
|
||||
|
||||
public Dictionary<string, List<FunctionModel>> CallableFunctionModels = new();
|
||||
|
||||
|
||||
public void RegisterFunctionModel([In] FunctionModel func)
|
||||
{
|
||||
if (!CallableFunctionModels.ContainsKey(func.module))
|
||||
CallableFunctionModels[func.module] = new();
|
||||
CallableFunctionModels[func.module].Add(func);
|
||||
Debug.Log($"[{String.Join(", ", func.returns.ToList().ConvertAll(x => $"{x.Key}: {x.Value}"))}] {func.name}" +
|
||||
$"({String.Join(", ", func.parameters.ToList().ConvertAll(x => $"{x.Key}: {x.Value}"))}): {func.description}");
|
||||
}
|
||||
public void UnregisterFunctionModel([In] FunctionModel func)
|
||||
{
|
||||
CallableFunctionModels[func.module].Remove(func);
|
||||
}
|
||||
public List<string> GetAllModuleName()
|
||||
{
|
||||
return CallableFunctionModels.Keys.ToList();
|
||||
}
|
||||
public List<string> GetAllFunctionName(string module)
|
||||
{
|
||||
return CallableFunctionModels[module].ConvertAll(x => x.name);
|
||||
}
|
||||
public bool ContainsModule(string module)
|
||||
{
|
||||
return CallableFunctionModels.ContainsKey(module);
|
||||
}
|
||||
public bool ContainsFunctionModel(string module, string functionName)
|
||||
{
|
||||
return ContainsModule(module) && CallableFunctionModels[module].Any(y => y.name == functionName);
|
||||
}
|
||||
public List<FunctionModel> GetAllFunctionModel(string module)
|
||||
{
|
||||
return CallableFunctionModels[module];
|
||||
}
|
||||
[return: ReturnMayNull]
|
||||
public FunctionModel GetFunctionModel(string module,string functionName)
|
||||
{
|
||||
if (ContainsModule(module))
|
||||
return CallableFunctionModels[module].FirstOrDefault(x => x.name == functionName);
|
||||
return null;
|
||||
}
|
||||
|
||||
public delegate bool CustomTransformer([In] string word, out string late);
|
||||
public List<CustomTransformer> customTransformers = new();
|
||||
public static string Transformer([In] string str)
|
||||
{
|
||||
if (string.IsNullOrEmpty(str))
|
||||
return str;
|
||||
if (instance != null)
|
||||
{
|
||||
foreach (var customTransformer in instance.customTransformers)
|
||||
{
|
||||
if (customTransformer(str, out var result))
|
||||
{
|
||||
var menuButton = instance.callbackDatas.Find(x => x.name == str);
|
||||
if (menuButton != null)
|
||||
{
|
||||
menuButton.name = result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (instance.TextLabels == null)
|
||||
return str;
|
||||
if (instance.TextLabels.symbols.ContainsKey(str))
|
||||
return instance.TextLabels.symbols[str];
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public void SetupWorkflowGraphNodeType([In] SharedModule.CallbackData callback)
|
||||
{
|
||||
callbackDatas.Add(callback);
|
||||
}
|
||||
public void SetupWorkflowGraphNodeType(params NodeInfo[] templates)
|
||||
{
|
||||
foreach (NodeInfo nodeInfo in templates)
|
||||
{
|
||||
if (registeredCallbackNodeType.Contains(nodeInfo.GetType()))
|
||||
continue;
|
||||
registeredCallbackNodeType.Add(nodeInfo.GetType());
|
||||
string label = nodeInfo.GetType().Name;
|
||||
if (label.EndsWith("Info"))
|
||||
label = label[..^4];
|
||||
SetupWorkflowGraphNodeType(new SharedModule.CallbackData(Transformer(label), x =>
|
||||
{
|
||||
var info = nodeInfo.TemplateClone();
|
||||
var node = this.CreateGraphNode(info);
|
||||
var pos = focusObject.position;
|
||||
node.transform.position = new Vector2(pos.x, pos.y);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
callbackDatas = new();
|
||||
Architecture.RegisterWithDuplicateAllow(typeof(WorkflowManager), this, () =>
|
||||
{
|
||||
Debug.Log($"{nameof(WorkflowManager)} registered");
|
||||
if (GraphNodePrefabs == null)
|
||||
GraphNodePrefabs = Resources.Load<ScriptableObject>("Workflow/Nodes");
|
||||
SetupWorkflowGraphNodeType(
|
||||
new TextNodeInfo(),
|
||||
new ValueNodeInfo(),
|
||||
new ResourceNodeInfo(),
|
||||
new StepNodeInfo(),
|
||||
new EndNodeInfo());
|
||||
}, typeof(GraphInputWindow), typeof(GraphInspector));
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (Keyboard.current[Key.LeftCtrl].isPressed)
|
||||
{
|
||||
var t = -Mouse.current.scroll.y.ReadValue() * ScrollSpeed * 0.001f;
|
||||
var z = m_CameraTransform.transform.localPosition.z;
|
||||
if (z - t > -100 && z - t < -5)
|
||||
m_CameraTransform.transform.Translate(new Vector3(0, 0, -t), Space.Self);
|
||||
}
|
||||
UIFocusObject.position = Mouse.current.position.ReadValue();
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
CameraZ = Camera.main.transform.position.z;
|
||||
}
|
||||
public void RefreshImmediate()
|
||||
{
|
||||
foreach (var node in workflow.Nodes)
|
||||
{
|
||||
node.RefreshImmediate();
|
||||
}
|
||||
}
|
||||
public void ClearWorkflowGraph()
|
||||
{
|
||||
foreach (var node in workflow.Nodes)
|
||||
{
|
||||
GameObject.Destroy(node.gameObject);
|
||||
}
|
||||
workflow.Nodes.Clear();
|
||||
workflow.Datas.Clear();
|
||||
}
|
||||
public void BuildWorkflowGraph()
|
||||
{
|
||||
foreach (var info in workflow.Datas)
|
||||
{
|
||||
CreateGraphNode(info);
|
||||
}
|
||||
}
|
||||
|
||||
public Node CreateGraphNode([In] NodeInfo info, bool isRefresh = true)
|
||||
{
|
||||
var node = info.Instantiate();
|
||||
node.gameObject.SetActive(true);
|
||||
node.transform.SetParent(ContentPlane);
|
||||
node.transform.localScale = Vector3.one;
|
||||
node.transform.eulerAngles = Vector3.zero;
|
||||
node.SetupFromInfo(info.TemplateClone(), isRefresh);
|
||||
workflow.Nodes.Add(node);
|
||||
node.MyNodeTab = GraphInputWindow.instance.RegisterOnHierarchyWindow(node.info);
|
||||
return node;
|
||||
}
|
||||
public void DestroyNode(Node node)
|
||||
{
|
||||
if (!workflow.Nodes.Remove(node))
|
||||
{
|
||||
throw new InvalidOperationException("node is not in current workflow");
|
||||
}
|
||||
GameObject.Destroy(node.gameObject);
|
||||
}
|
||||
public bool ContainsNode(int id)
|
||||
{
|
||||
if (id < 0)
|
||||
return false;
|
||||
return workflow.Nodes.Count < id;
|
||||
}
|
||||
public Node GetGraphNode(int id)
|
||||
{
|
||||
if (id < 0)
|
||||
return null;
|
||||
return workflow.Nodes[id];
|
||||
}
|
||||
public int GetGraphNodeID(Node node)
|
||||
{
|
||||
if (node == null)
|
||||
return -1;
|
||||
return workflow.Nodes.IndexOf(node);
|
||||
}
|
||||
|
||||
public void SaveWorkflowWithSystemPlugin()
|
||||
{
|
||||
var str = PluginExtenion.SaveFile("工作流|*.workflow;*.json", "保存工作流");
|
||||
if (string.IsNullOrEmpty(str) == false)
|
||||
SaveWorkflow(str);
|
||||
}
|
||||
public void LoadWorkflowWithSystemPlugin()
|
||||
{
|
||||
var str = PluginExtenion.SelectFile("工作流|*.workflow;*.json", "加载工作流");
|
||||
if (string.IsNullOrEmpty(str) == false)
|
||||
LoadWorkflow(str);
|
||||
}
|
||||
|
||||
[Content, OnlyPlayMode] public string LastSavePath = null;
|
||||
|
||||
public static string WorkflowFileKey = "workflow";
|
||||
|
||||
public ToolFile SaveWorkflow(string workflowPath)
|
||||
{
|
||||
LastSavePath = workflowPath;
|
||||
ToolFile local = new(workflowPath);
|
||||
ToolFile parent = local.GetParentDir();
|
||||
if (parent.Exists() == false)
|
||||
throw new FileNotFoundException($"{parent} is not exist");
|
||||
workflow.Datas.Clear();
|
||||
Debug.Log(workflow.Nodes.Count);
|
||||
foreach (var node in workflow.Nodes)
|
||||
{
|
||||
node.info.CopyFromNode(node);
|
||||
workflow.Datas.Add(node.info);
|
||||
}
|
||||
local.SaveAsJson(workflow, WorkflowFileKey);
|
||||
return local;
|
||||
}
|
||||
|
||||
public Workflow LoadWorkflow(Workflow workflow)
|
||||
{
|
||||
ClearWorkflowGraph();
|
||||
workflow.Datas.Sort((x, y) => x.nodeID.CompareTo(y.nodeID));
|
||||
for (int i = 0; i < workflow.Datas.Count; i++)
|
||||
{
|
||||
if (workflow.Datas[i].nodeID != i)
|
||||
throw new InvalidOperationException("Bad workflow: nodeID != node index");
|
||||
}
|
||||
this.m_workflow = new();
|
||||
foreach (var info in workflow.Datas)
|
||||
{
|
||||
var node = CreateGraphNode(info, false);
|
||||
this.workflow.Datas.Add(node.info);
|
||||
node.ClearSlots();
|
||||
node.BuildSlots();
|
||||
}
|
||||
ConventionUtility.CreateSteps().Next(() =>
|
||||
{
|
||||
for (int i = 0; i < workflow.Datas.Count; i++)
|
||||
{
|
||||
var info = workflow.Datas[i];
|
||||
var node = GetGraphNode(i);
|
||||
foreach (var (key, slot) in info.inmapping)
|
||||
{
|
||||
if (slot.targetNodeID != -1)
|
||||
this.workflow.Nodes[i].LinkInslotToOtherNodeOutslot(GetGraphNode(slot.targetNodeID), slot.slotName, slot.targetSlotName);
|
||||
}
|
||||
node.RefreshRectTransform();
|
||||
node.RefreshPosition();
|
||||
}
|
||||
}).Wait(0.1f, () =>
|
||||
{
|
||||
foreach (var node in this.workflow.Nodes)
|
||||
{
|
||||
node.RefreshImmediate();
|
||||
}
|
||||
}).Wait(1f, () =>
|
||||
{
|
||||
foreach (var node in this.workflow.Nodes)
|
||||
{
|
||||
node.RefreshImmediate();
|
||||
}
|
||||
}).Invoke();
|
||||
Debug.Log($"Current Workflow Nodes: count={this.workflow.Nodes.Count}");
|
||||
return this.workflow;
|
||||
}
|
||||
public Workflow LoadWorkflow(string workflowPath)
|
||||
{
|
||||
ToolFile local = new(workflowPath);
|
||||
if (local.Exists() == false)
|
||||
throw new FileNotFoundException($"{local} is not exist");
|
||||
LastSavePath = workflowPath;
|
||||
var loadedWorkflow = local.LoadAsJson<Workflow>(WorkflowFileKey);
|
||||
return LoadWorkflow(loadedWorkflow);
|
||||
}
|
||||
public void OpenMenu(PointerEventData data)
|
||||
{
|
||||
focusObject.position = data.pointerCurrentRaycast.worldPosition;
|
||||
#if UNITY_EDITOR
|
||||
if (callbackDatas.Count == 0)
|
||||
SharedModule.instance.OpenCustomMenu(UIFocusObject, new SharedModule.CallbackData("Empty", x => Debug.Log(x)));
|
||||
else
|
||||
#endif
|
||||
{
|
||||
foreach (var callbackData in callbackDatas)
|
||||
{
|
||||
Transformer(callbackData.name);
|
||||
}
|
||||
SharedModule.instance.OpenCustomMenu(UIFocusObject, callbackDatas.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Convention/[Visual]/Workflow/WorkflowManager.cs.meta
Normal file
11
Convention/[Visual]/Workflow/WorkflowManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd45ab603848a8147a3b02553e5bc1ba
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user