From a1307c6eff6645a15192ab94060f22f3480a8f9c Mon Sep 17 00:00:00 2001 From: Lwmte <3331699+Lwmte@users.noreply.github.com> Date: Sun, 15 Mar 2026 09:16:32 +0100 Subject: [PATCH 1/4] Added warning for unsupported node event types --- TombEditor/Controls/TriggerManager.cs | 7 ++++ TombEditor/Forms/FormEventSetEditor.cs | 2 + .../Controls/VisualScripting/NodeEditor.cs | 40 +++++++++++++++++-- .../TriggerNodeEnumerations.cs | 14 +++++++ TombLib/TombLib/Utils/ScriptingUtils.cs | 23 +++++++++++ 5 files changed, 83 insertions(+), 3 deletions(-) diff --git a/TombEditor/Controls/TriggerManager.cs b/TombEditor/Controls/TriggerManager.cs index 4e8b890ffd..a04053a059 100644 --- a/TombEditor/Controls/TriggerManager.cs +++ b/TombEditor/Controls/TriggerManager.cs @@ -24,6 +24,13 @@ public TriggerManager() InitializeComponent(); } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public EventType? EventType + { + get { return nodeEditor.CurrentEventType; } + set { nodeEditor.CurrentEventType = value; } + } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public Event Event { diff --git a/TombEditor/Forms/FormEventSetEditor.cs b/TombEditor/Forms/FormEventSetEditor.cs index 6b6b37ae76..6284e71754 100644 --- a/TombEditor/Forms/FormEventSetEditor.cs +++ b/TombEditor/Forms/FormEventSetEditor.cs @@ -429,6 +429,7 @@ private void LoadEventSetIntoUI(EventSet newEventSet) } cbEvents.SelectedItem = newEventSet.LastUsedEvent; + triggerManager.EventType = newEventSet.LastUsedEvent; triggerManager.Event = newEventSet.Events[newEventSet.LastUsedEvent]; tbName.Text = newEventSet.Name; @@ -646,6 +647,7 @@ private void cbEvents_SelectedIndexChanged(object sender, EventArgs e) if (!_lockUI) { SelectedSet.LastUsedEvent = (EventType)cbEvents.SelectedItem; + triggerManager.EventType = SelectedSet.LastUsedEvent; triggerManager.Event = SelectedSet.Events[SelectedSet.LastUsedEvent]; } } diff --git a/TombLib/TombLib.Forms/Controls/VisualScripting/NodeEditor.cs b/TombLib/TombLib.Forms/Controls/VisualScripting/NodeEditor.cs index da24befb8a..8867957991 100644 --- a/TombLib/TombLib.Forms/Controls/VisualScripting/NodeEditor.cs +++ b/TombLib/TombLib.Forms/Controls/VisualScripting/NodeEditor.cs @@ -73,6 +73,10 @@ public List Nodes [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public List NodeFunctions { get; private set; } = new List(); + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public EventType? CurrentEventType { get; set; } + // Precache lists of objects to avoid polling every time user changes function // in a node list. By default it is set to nothing, but must be replaced externally // by a form/control where node editor is placed. @@ -885,20 +889,50 @@ private void DrawShadow(PaintEventArgs e, VisibleNodeBase node) e.Graphics.DrawImage(Properties.Resources.misc_Shadow, rect); } + private bool IsNodeUnsupported(TriggerNode node) + { + if (!CurrentEventType.HasValue || string.IsNullOrEmpty(node.Function)) + return false; + + var func = NodeFunctions.FirstOrDefault(f => f.Signature == node.Function); + if (func == null) + return false; + + return func.IsUnsupported(CurrentEventType.Value); + } + private void DrawHeader(PaintEventArgs e, VisibleNodeBase node) { if (!node.Visible) return; - var size = TextRenderer.MeasureText(node.Node.Name, Font); + const float LabelOpacity = 0.5f; + + bool unsupported = IsNodeUnsupported(node.Node); + var headerText = unsupported ? "Not supported for this event type" : node.Node.Name; + int iconOffset = 0; + var size = TextRenderer.MeasureText(headerText, Font); var rect = node.ClientRectangle; rect.Height = size.Height; rect.Offset(node.Location); rect.Offset(0, -(int)(size.Height * 1.2f)); - using (var b = new SolidBrush(Colors.LightText.ToFloat3Color().ToWinFormsColor(0.5f))) - e.Graphics.DrawString(node.Node.Name, Font, b, rect, + if (unsupported) + { + var matrix = new System.Drawing.Imaging.ColorMatrix { Matrix33 = LabelOpacity, Matrix22 = 0.0f }; + var attributes = new System.Drawing.Imaging.ImageAttributes(); + attributes.SetColorMatrix(matrix, System.Drawing.Imaging.ColorMatrixFlag.Default, System.Drawing.Imaging.ColorAdjustType.Bitmap); + + var icon = Properties.Resources.general_Warning_16; + var iconRect = new Rectangle(rect.X, rect.Y + (rect.Height - icon.Height), icon.Width, icon.Height); + e.Graphics.DrawImage(icon, iconRect, 0, 0, icon.Width, icon.Height, GraphicsUnit.Pixel, attributes); + iconOffset = icon.Width + 2; + } + + var textRect = new Rectangle(rect.X + iconOffset, rect.Y, rect.Width - iconOffset, rect.Height); + using (var b = new SolidBrush(Colors.LightText.ToFloat3Color().ToWinFormsColor(LabelOpacity))) + e.Graphics.DrawString(headerText, Font, b, textRect, new StringFormat { Alignment = StringAlignment.Near, LineAlignment = StringAlignment.Center }); var condNode = node as VisibleNodeCondition; diff --git a/TombLib/TombLib/LevelData/VisualScripting/TriggerNodeEnumerations.cs b/TombLib/TombLib/LevelData/VisualScripting/TriggerNodeEnumerations.cs index 08e1e09650..4e0da52f29 100644 --- a/TombLib/TombLib/LevelData/VisualScripting/TriggerNodeEnumerations.cs +++ b/TombLib/TombLib/LevelData/VisualScripting/TriggerNodeEnumerations.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using TombLib.LevelData; namespace TombLib.LevelData.VisualScripting { @@ -78,6 +79,19 @@ public class NodeFunction public bool Conditional { get; set; } public string Signature { get; set; } public List Arguments { get; private set; } = new List(); + public List SupportedEvents { get; private set; } = new List(); + public List UnsupportedEvents { get; private set; } = new List(); + + public bool IsUnsupported(EventType eventType) + { + if (SupportedEvents.Count > 0 && !SupportedEvents.Contains(eventType)) + return true; + + if (UnsupportedEvents.Count > 0 && UnsupportedEvents.Contains(eventType)) + return true; + + return false; + } public override string ToString() => Name; public override int GetHashCode() => (Name + Conditional.ToString() + Description + Signature + Arguments.Count.ToString()).GetHashCode(); diff --git a/TombLib/TombLib/Utils/ScriptingUtils.cs b/TombLib/TombLib/Utils/ScriptingUtils.cs index e0b0daf77f..adad2e4a98 100644 --- a/TombLib/TombLib/Utils/ScriptingUtils.cs +++ b/TombLib/TombLib/Utils/ScriptingUtils.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using TombLib.LevelData; using TombLib.LevelData.VisualScripting; namespace TombLib.Utils @@ -59,6 +60,8 @@ public static class ScriptingUtils private const string _nodeTypeId = _metadataPrefix + "condition"; private const string _nodeArgumentId = _metadataPrefix + "arguments"; private const string _nodeDescriptionId = _metadataPrefix + "description"; + private const string _nodeSupportedId = _metadataPrefix + "supported"; + private const string _nodeUnsupportedId = _metadataPrefix + "unsupported"; private const string _nodeLayoutNewLine = "newline"; public static string GameNodeScriptPath = Path.Combine("Scripts", "Engine", "NodeCatalogs"); @@ -156,6 +159,16 @@ private static List GetAllNodeFunctions(string path, List 0) @@ -257,6 +270,16 @@ private static List GetAllNodeFunctions(string path, List n.Section).ToList(); } + private static void ParseEventTypeList(string comment, string tagId, List targetList) + { + var values = TextExtensions.ExtractValues(comment.Substring(tagId.Length, comment.Length - tagId.Length)); + foreach (var v in values) + { + if (Enum.TryParse(v.Trim(), out EventType eventType)) + targetList.Add(eventType); + } + } + public static List GetAllFunctionNames(string path, List list = null, int depth = 0) { var result = list == null ? new List() : list; From 1828cd57dead2424547272b18bf08337531006c4 Mon Sep 17 00:00:00 2001 From: Lwmte <3331699+Lwmte@users.noreply.github.com> Date: Sun, 15 Mar 2026 09:17:44 +0100 Subject: [PATCH 2/4] Use non-nullable type --- TombEditor/Controls/TriggerManager.cs | 2 +- TombLib/TombLib.Forms/Controls/VisualScripting/NodeEditor.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/TombEditor/Controls/TriggerManager.cs b/TombEditor/Controls/TriggerManager.cs index a04053a059..30b5847f74 100644 --- a/TombEditor/Controls/TriggerManager.cs +++ b/TombEditor/Controls/TriggerManager.cs @@ -25,7 +25,7 @@ public TriggerManager() } [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public EventType? EventType + public EventType EventType { get { return nodeEditor.CurrentEventType; } set { nodeEditor.CurrentEventType = value; } diff --git a/TombLib/TombLib.Forms/Controls/VisualScripting/NodeEditor.cs b/TombLib/TombLib.Forms/Controls/VisualScripting/NodeEditor.cs index 8867957991..4b75db4df9 100644 --- a/TombLib/TombLib.Forms/Controls/VisualScripting/NodeEditor.cs +++ b/TombLib/TombLib.Forms/Controls/VisualScripting/NodeEditor.cs @@ -75,7 +75,7 @@ public List Nodes [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public EventType? CurrentEventType { get; set; } + public EventType CurrentEventType { get; set; } // Precache lists of objects to avoid polling every time user changes function // in a node list. By default it is set to nothing, but must be replaced externally From 22a81adec41e0a9a4bf1f6a78f03bd7af9a3a24a Mon Sep 17 00:00:00 2001 From: Lwmte <3331699+Lwmte@users.noreply.github.com> Date: Sun, 15 Mar 2026 09:59:10 +0100 Subject: [PATCH 3/4] Update NodeEditor.cs --- .../Controls/VisualScripting/NodeEditor.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/TombLib/TombLib.Forms/Controls/VisualScripting/NodeEditor.cs b/TombLib/TombLib.Forms/Controls/VisualScripting/NodeEditor.cs index 4b75db4df9..2e3ce481f6 100644 --- a/TombLib/TombLib.Forms/Controls/VisualScripting/NodeEditor.cs +++ b/TombLib/TombLib.Forms/Controls/VisualScripting/NodeEditor.cs @@ -25,6 +25,10 @@ public enum ConnectionMode public partial class NodeEditor : UserControl { + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public EventType CurrentEventType { get; set; } + [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public Vector2 ViewPosition { get; set; } = new Vector2(60.0f, 60.0f); @@ -73,10 +77,6 @@ public List Nodes [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public List NodeFunctions { get; private set; } = new List(); - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public EventType CurrentEventType { get; set; } - // Precache lists of objects to avoid polling every time user changes function // in a node list. By default it is set to nothing, but must be replaced externally // by a form/control where node editor is placed. @@ -891,14 +891,14 @@ private void DrawShadow(PaintEventArgs e, VisibleNodeBase node) private bool IsNodeUnsupported(TriggerNode node) { - if (!CurrentEventType.HasValue || string.IsNullOrEmpty(node.Function)) + if (string.IsNullOrEmpty(node.Function)) return false; var func = NodeFunctions.FirstOrDefault(f => f.Signature == node.Function); if (func == null) return false; - return func.IsUnsupported(CurrentEventType.Value); + return func.IsUnsupported(CurrentEventType); } private void DrawHeader(PaintEventArgs e, VisibleNodeBase node) From 2388d60635c3f2d6589067a93ecc3e175866ff00 Mon Sep 17 00:00:00 2001 From: Lwmte <3331699+Lwmte@users.noreply.github.com> Date: Sun, 15 Mar 2026 11:29:42 +0100 Subject: [PATCH 4/4] Update Readme.md --- TombLib/TombLib/Catalogs/TEN Node Catalogs/Readme.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/TombLib/TombLib/Catalogs/TEN Node Catalogs/Readme.md b/TombLib/TombLib/Catalogs/TEN Node Catalogs/Readme.md index a20dcacdf6..b2b8b3db8d 100644 --- a/TombLib/TombLib/Catalogs/TEN Node Catalogs/Readme.md +++ b/TombLib/TombLib/Catalogs/TEN Node Catalogs/Readme.md @@ -40,6 +40,14 @@ Comment metadata entry reference (metadata block is indicated by a keyword which new line. - **!Section "SECTION"** - this will define where the node will be found inside Tomb Editor. + + - **!Supported "TYPE" "TYPE" "..." - defines supported event types for a given node. Each event type should be + enclosed in quotes. If event is not supported by a node, it will display a warning message when misplaced. + Possible event types are: **OnVolumeEnter, OnVolumeInside, OnVolumeLeave, OnLoop, OnLoadGame, OnSaveGame, + OnLevelStart, OnLevelEnd, OnUseItem, OnFreeze**. + + - **!Unsupported "TYPE" "TYPE" "..." - defines unsupported event types for a given node. Acts in an opposite way + to `!Supported`. Possible event types are equal to `!Supported`. - **!Arguments "ARGDESC1" "ARGDESC2" "ARGDESC..."** - infinite amount of args, with **ARGDESC** parameters separated by commas as follows: