update forge
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 27s
Create tag and build when new code gets to main / Export (push) Successful in 7m25s

This commit is contained in:
2026-05-17 00:06:44 +02:00
parent 8b54f00814
commit e09714cf83
473 changed files with 13577 additions and 767 deletions

View File

@@ -16,7 +16,15 @@ namespace Gamesmiths.Forge.Godot.Editor.Statescript;
[Tool]
internal sealed partial class SharedVariableSetEditorProperty : EditorProperty, ISerializationListener
{
private const string BackgroundPanelNodeName = "BackgroundPanel";
private const string RootNodeName = "Root";
private const string HeaderRowNodeName = "HeaderRow";
private const string AddButtonNodeName = "AddButton";
private const string VariableListNodeName = "VariableList";
private const string VariableNameButtonMetaKey = "_shared_variable_name_button";
private static readonly Color _variableColor = new(0xe5c07bff);
private static readonly Color _highlightColor = new(0x56b6c2ff);
private readonly HashSet<string> _expandedArrays = [];
@@ -33,6 +41,7 @@ internal sealed partial class SharedVariableSetEditorProperty : EditorProperty,
private Texture2D? _addIcon;
private Texture2D? _removeIcon;
private string? _selectedVariableName;
/// <summary>
/// Sets the <see cref="EditorUndoRedoManager"/> used for undo/redo support.
@@ -45,11 +54,21 @@ internal sealed partial class SharedVariableSetEditorProperty : EditorProperty,
public override void _Ready()
{
base._Ready();
SharedVariableHighlightState.Changed += OnSharedVariableHighlightChanged;
_addIcon = EditorInterface.Singleton.GetEditorTheme().GetIcon("Add", "EditorIcons");
_removeIcon = EditorInterface.Singleton.GetEditorTheme().GetIcon("Remove", "EditorIcons");
if (GetEditedObject() is ForgeSharedVariableSet sharedVariableSet)
{
SharedVariableHighlightState.SetInspectorContext(sharedVariableSet.ResourcePath);
SharedVariableHighlightState.SetSelection(sharedVariableSet.ResourcePath, _selectedVariableName);
}
var backgroundPanel = new PanelContainer
{
Name = BackgroundPanelNodeName,
SizeFlagsHorizontal = SizeFlags.ExpandFill,
};
@@ -70,14 +89,19 @@ internal sealed partial class SharedVariableSetEditorProperty : EditorProperty,
AddChild(backgroundPanel);
SetBottomEditor(backgroundPanel);
_root = new VBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill };
_root = new VBoxContainer
{
Name = RootNodeName,
SizeFlagsHorizontal = SizeFlags.ExpandFill,
};
backgroundPanel.AddChild(_root);
var headerHBox = new HBoxContainer();
var headerHBox = new HBoxContainer { Name = HeaderRowNodeName };
_root.AddChild(headerHBox);
_addButton = new Button
{
Name = AddButtonNodeName,
Text = "Add Variable",
SizeFlagsHorizontal = SizeFlags.ExpandFill,
};
@@ -87,34 +111,55 @@ internal sealed partial class SharedVariableSetEditorProperty : EditorProperty,
_root.AddChild(new HSeparator());
_variableList = new VBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill };
_variableList = new VBoxContainer
{
Name = VariableListNodeName,
SizeFlagsHorizontal = SizeFlags.ExpandFill,
};
_root.AddChild(_variableList);
}
public override void _UpdateProperty()
{
EnsureControlsCached();
if (GetEditedObject() is ForgeSharedVariableSet sharedVariableSet)
{
SharedVariableHighlightState.SetInspectorContext(sharedVariableSet.ResourcePath);
}
SyncSelectedVariableFromHighlightState();
RebuildList();
}
public override void _ExitTree()
{
SharedVariableHighlightState.Changed -= OnSharedVariableHighlightChanged;
if (GetEditedObject() is ForgeSharedVariableSet sharedVariableSet)
{
SharedVariableHighlightState.ClearInspectorContext(sharedVariableSet.ResourcePath);
}
ReleaseUiState();
FreeAllChildren();
base._ExitTree();
}
public void OnBeforeSerialize()
{
if (_addButton is not null)
{
_addButton.Pressed -= OnAddPressed;
}
ClearVariableList();
_creationDialog?.Free();
_creationDialog = null;
_newNameEdit = null;
_newTypeDropdown = null;
_newArrayToggle = null;
SharedVariableHighlightState.Changed -= OnSharedVariableHighlightChanged;
ReleaseUiState();
}
public void OnAfterDeserialize()
{
if (_addButton is not null)
EnsureControlsCached();
SharedVariableHighlightState.Changed += OnSharedVariableHighlightChanged;
SyncSelectedVariableFromHighlightState();
if (_addButton is not null && IsInstanceValid(_addButton))
{
_addButton.Pressed += OnAddPressed;
}
@@ -122,6 +167,28 @@ internal sealed partial class SharedVariableSetEditorProperty : EditorProperty,
RebuildList();
}
private static int FindTypeDropdownIndex(OptionButton dropdown, StatescriptVariableType variableType)
{
for (int i = 0; i < dropdown.ItemCount; i++)
{
if (dropdown.GetItemId(i) == (int)variableType)
{
return i;
}
}
return 0;
}
private static void UpdateVariableNameButtonAppearance(Button button, bool isSelected)
{
Color buttonColor = isSelected ? _highlightColor : _variableColor;
button.AddThemeColorOverride("font_color", buttonColor);
button.AddThemeColorOverride("font_pressed_color", buttonColor);
button.AddThemeColorOverride("font_hover_color", buttonColor.Lightened(0.2f));
button.AddThemeColorOverride("font_hover_pressed_color", buttonColor.Lightened(0.2f));
}
private Array<ForgeSharedVariableDefinition> GetDefinitions()
{
GodotObject obj = GetEditedObject();
@@ -133,7 +200,18 @@ internal sealed partial class SharedVariableSetEditorProperty : EditorProperty,
private void NotifyChanged()
{
if (GetEditedObject() is Resource resource)
GodotObject obj = GetEditedObject();
string propertyName = GetEditedProperty();
if (obj is not ForgeSharedVariableSet sharedVariableSet)
{
return;
}
obj.Set(propertyName, sharedVariableSet.Variables);
EmitChanged(propertyName, sharedVariableSet.Variables);
if (obj is Resource resource)
{
resource.EmitChanged();
}
@@ -141,35 +219,31 @@ internal sealed partial class SharedVariableSetEditorProperty : EditorProperty,
private void RebuildList()
{
EnsureControlsCached();
if (_variableList is null)
{
return;
}
// Defer the actual rebuild so that any in-progress signal emission (e.g. a button Pressed handler that
// triggered an add/remove) finishes before we free the emitting nodes.
CallDeferred(MethodName.RebuildListDeferred);
}
private void RebuildListDeferred()
{
if (_variableList is null)
{
return;
}
SyncSelectedVariableFromHighlightState();
ClearVariableList();
Array<ForgeSharedVariableDefinition> definitions = GetDefinitions();
for (var i = 0; i < definitions.Count; i++)
for (int i = 0; i < definitions.Count; i++)
{
AddVariableRow(definitions, i);
}
RefreshVariableSelectionVisuals();
}
private void ClearVariableList()
{
EnsureControlsCached();
if (_variableList is null)
{
return;
@@ -182,6 +256,75 @@ internal sealed partial class SharedVariableSetEditorProperty : EditorProperty,
}
}
private void EnsureControlsCached()
{
_root ??= GetNodeOrNull<VBoxContainer>(
$"{BackgroundPanelNodeName}/{RootNodeName}");
_addButton ??= GetNodeOrNull<Button>(
$"{BackgroundPanelNodeName}/{RootNodeName}/{HeaderRowNodeName}/{AddButtonNodeName}");
_variableList ??= GetNodeOrNull<VBoxContainer>(
$"{BackgroundPanelNodeName}/{RootNodeName}/{VariableListNodeName}");
}
private void ReleaseUiState()
{
if (_addButton is not null && IsInstanceValid(_addButton))
{
_addButton.Pressed -= OnAddPressed;
}
ClearVariableList();
if (_creationDialog is not null && IsInstanceValid(_creationDialog))
{
_creationDialog.Confirmed -= OnCreationConfirmed;
_creationDialog.Canceled -= OnCreationCanceled;
_creationDialog.Free();
}
_creationDialog = null;
_newNameEdit = null;
_newTypeDropdown = null;
_newArrayToggle = null;
_root = null;
_variableList = null;
_addButton = null;
}
private void FreeAllChildren()
{
for (int i = GetChildCount() - 1; i >= 0; i--)
{
Node child = GetChild(i);
RemoveChild(child);
child.Free();
}
}
private void OnSharedVariableHighlightChanged()
{
SyncSelectedVariableFromHighlightState();
RefreshVariableSelectionVisuals();
}
private void SyncSelectedVariableFromHighlightState()
{
if (GetEditedObject() is not ForgeSharedVariableSet sharedVariableSet)
{
_selectedVariableName = null;
return;
}
if (SharedVariableHighlightState.TryGetActiveSelection(out string selectedSetPath, out string variableName)
&& string.Equals(selectedSetPath, sharedVariableSet.ResourcePath, System.StringComparison.Ordinal))
{
_selectedVariableName = variableName;
return;
}
_selectedVariableName = null;
}
private void AddVariableRow(Array<ForgeSharedVariableDefinition> definitions, int index)
{
if (_variableList is null || index < 0 || index >= definitions.Count)
@@ -197,17 +340,25 @@ internal sealed partial class SharedVariableSetEditorProperty : EditorProperty,
var headerRow = new HBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill };
rowContainer.AddChild(headerRow);
var nameLabel = new Label
bool isSelected = _selectedVariableName == def.VariableName;
var nameButton = new Button
{
Text = def.VariableName,
SizeFlagsHorizontal = SizeFlags.ExpandFill,
Flat = true,
ToggleMode = true,
ButtonPressed = isSelected,
Alignment = HorizontalAlignment.Left,
};
nameLabel.AddThemeColorOverride("font_color", _variableColor);
nameLabel.AddThemeFontOverride(
nameButton.SetMeta(VariableNameButtonMetaKey, def.VariableName);
UpdateVariableNameButtonAppearance(nameButton, isSelected);
nameButton.AddThemeFontOverride(
"font",
EditorInterface.Singleton.GetEditorTheme().GetFont("bold", "EditorFonts"));
headerRow.AddChild(nameLabel);
nameButton.Toggled += pressed => SetSelectedVariable(def.VariableName, pressed);
headerRow.AddChild(nameButton);
var typeLabel = new Label
{
@@ -218,7 +369,7 @@ internal sealed partial class SharedVariableSetEditorProperty : EditorProperty,
typeLabel.AddThemeColorOverride("font_color", new Color(0.6f, 0.6f, 0.6f));
headerRow.AddChild(typeLabel);
var capturedIndex = index;
int capturedIndex = index;
var deleteButton = new Button
{
@@ -245,6 +396,56 @@ internal sealed partial class SharedVariableSetEditorProperty : EditorProperty,
rowContainer.AddChild(new HSeparator());
}
private void SetSelectedVariable(string variableName, bool selected)
{
if (selected)
{
_selectedVariableName = variableName;
}
else if (_selectedVariableName == variableName)
{
_selectedVariableName = null;
}
if (GetEditedObject() is ForgeSharedVariableSet sharedVariableSet)
{
SharedVariableHighlightState.SetInspectorContext(sharedVariableSet.ResourcePath);
SharedVariableHighlightState.SetSelection(sharedVariableSet.ResourcePath, _selectedVariableName);
}
else
{
SharedVariableHighlightState.SetSelection(null, null);
}
RefreshVariableSelectionVisuals();
}
private void RefreshVariableSelectionVisuals()
{
if (_variableList is null)
{
return;
}
RefreshVariableSelectionVisualsRecursive(_variableList);
}
private void RefreshVariableSelectionVisualsRecursive(Node parent)
{
foreach (Node child in parent.GetChildren())
{
if (child is Button button && button.HasMeta(VariableNameButtonMetaKey))
{
string variableName = button.GetMeta(VariableNameButtonMetaKey).AsString();
bool isSelected = _selectedVariableName == variableName;
button.SetPressedNoSignal(isSelected);
UpdateVariableNameButtonAppearance(button, isSelected);
}
RefreshVariableSelectionVisualsRecursive(child);
}
}
private Control CreateValueEditor(ForgeSharedVariableDefinition def)
{
if (def.VariableType == StatescriptVariableType.Bool)
@@ -310,7 +511,7 @@ internal sealed partial class SharedVariableSetEditorProperty : EditorProperty,
var headerRow = new HBoxContainer();
vBox.AddChild(headerRow);
var isExpanded = _expandedArrays.Contains(def.VariableName);
bool isExpanded = _expandedArrays.Contains(def.VariableName);
var elementsContainer = new VBoxContainer
{
@@ -330,7 +531,7 @@ internal sealed partial class SharedVariableSetEditorProperty : EditorProperty,
{
elementsContainer.Visible = x;
var wasExpanded = !x;
bool wasExpanded = !x;
if (x)
{
@@ -379,9 +580,9 @@ internal sealed partial class SharedVariableSetEditorProperty : EditorProperty,
vBox.AddChild(elementsContainer);
for (var i = 0; i < def.InitialArrayValues.Count; i++)
for (int i = 0; i < def.InitialArrayValues.Count; i++)
{
var capturedIndex = i;
int capturedIndex = i;
if (def.VariableType == StatescriptVariableType.Bool)
{
@@ -502,7 +703,7 @@ internal sealed partial class SharedVariableSetEditorProperty : EditorProperty,
private void AddArrayElement(ForgeSharedVariableDefinition def, Variant value)
{
var wasExpanded = _expandedArrays.Contains(def.VariableName);
bool wasExpanded = _expandedArrays.Contains(def.VariableName);
if (_undoRedo is not null)
{
@@ -583,6 +784,8 @@ internal sealed partial class SharedVariableSetEditorProperty : EditorProperty,
(int)variableType);
}
_newTypeDropdown.Selected = FindTypeDropdownIndex(_newTypeDropdown, StatescriptVariableType.Int);
typeRow.AddChild(_newTypeDropdown);
var arrayRow = new HBoxContainer();
@@ -605,7 +808,7 @@ internal sealed partial class SharedVariableSetEditorProperty : EditorProperty,
return;
}
var name = _newNameEdit.Text.Trim();
string name = _newNameEdit.Text.Trim();
if (string.IsNullOrEmpty(name))
{