Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b198aba09b | |||
| 37165d1562 | |||
| 5684561b66 | |||
| 2678cac0e6 | |||
| 230b409abe | |||
| a6c80206c9 | |||
| 1a73f23670 | |||
| 38e62dcbb3 | |||
| 19bdc143c1 | |||
| 1709554e72 |
@@ -25,19 +25,24 @@ jobs:
|
|||||||
apt update && apt -y install curl nodejs xvfb
|
apt update && apt -y install curl nodejs xvfb
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
lfs: false
|
lfs: false
|
||||||
persist-credentials: true
|
|
||||||
|
|
||||||
- name: Checkout LFS
|
- name: Checkout LFS
|
||||||
run: |
|
run: |
|
||||||
git lfs install --local
|
UrlBase=$GITHUB_SERVER_URL; \
|
||||||
AUTH=$(git config http.${{ gitea.server_url }}/.extraheader)
|
UrlLfsBase=$UrlBase/${{ gitea.repository }}.git/info/lfs/objects; \
|
||||||
AUTH_FILE=$(git config includeif.gitdir:/workspace/${{ gitea.repository }}/.git.path)
|
Auth=`/usr/bin/git config --get --local http.$UrlBase/.extraheader`; \
|
||||||
git config -f $AUTH_FILE --unset http.${{ gitea.server_url }}/.extraheader
|
/usr/bin/git config --local http.${UrlLfsBase}/batch.extraheader "$Auth"; \
|
||||||
git config -f $AUTH_FILE http.${{ gitea.server_url }}/${{ gitea.repository }}.git/info/lfs/objects/batch.extraheader "$AUTH"
|
/usr/bin/git config --local http.${UrlLfsBase}/.extraheader ''
|
||||||
git lfs pull
|
|
||||||
|
git config --local lfs.transfer.maxretries 1
|
||||||
|
|
||||||
|
/usr/bin/git lfs fetch origin refs/remotes/origin/${{ gitea.ref_name }}
|
||||||
|
/usr/bin/git lfs checkout
|
||||||
|
/usr/bin/git add .
|
||||||
|
/usr/bin/git reset --hard
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
uses: godot-gdunit-labs/gdUnit4-action@v1
|
uses: godot-gdunit-labs/gdUnit4-action@v1
|
||||||
|
|||||||
@@ -36,48 +36,48 @@ jobs:
|
|||||||
INITIAL_VERSION: 0.1.0
|
INITIAL_VERSION: 0.1.0
|
||||||
DEFAULT_BUMP: patch
|
DEFAULT_BUMP: patch
|
||||||
|
|
||||||
Test:
|
# Test:
|
||||||
runs-on: ubuntu-latest
|
# runs-on: ubuntu-latest
|
||||||
env:
|
# env:
|
||||||
RUNNER_TOOL_CACHE: /toolcache # Runner Tool Cache
|
# RUNNER_TOOL_CACHE: /toolcache # Runner Tool Cache
|
||||||
steps:
|
# steps:
|
||||||
- name: Install node, xvfb and curl
|
# - name: Install node, xvfb and curl
|
||||||
run: |
|
# run: |
|
||||||
apt update && apt -y install curl nodejs xvfb
|
# apt update && apt -y install curl nodejs xvfb
|
||||||
|
#
|
||||||
- name: Checkout
|
# - name: Checkout
|
||||||
uses: actions/checkout@v6
|
# uses: actions/checkout@v6
|
||||||
with:
|
# with:
|
||||||
lfs: false
|
# lfs: false
|
||||||
persist-credentials: true
|
# persist-credentials: true
|
||||||
|
#
|
||||||
- name: Checkout LFS
|
# - name: Checkout LFS
|
||||||
run: |
|
# run: |
|
||||||
git lfs install --local
|
# git lfs install --local
|
||||||
AUTH=$(git config http.${{ gitea.server_url }}/.extraheader)
|
# AUTH=$(git config http.${{ gitea.server_url }}/.extraheader)
|
||||||
AUTH_FILE=$(git config includeif.gitdir:/workspace/${{ gitea.repository }}/.git.path)
|
# AUTH_FILE=$(git config includeif.gitdir:/workspace/${{ gitea.repository }}/.git.path)
|
||||||
git config -f $AUTH_FILE --unset http.${{ gitea.server_url }}/.extraheader
|
# git config -f $AUTH_FILE --unset http.${{ gitea.server_url }}/.extraheader
|
||||||
git config -f $AUTH_FILE http.${{ gitea.server_url }}/${{ gitea.repository }}.git/info/lfs/objects/batch.extraheader "$AUTH"
|
# git config -f $AUTH_FILE http.${{ gitea.server_url }}/${{ gitea.repository }}.git/info/lfs/objects/batch.extraheader "$AUTH"
|
||||||
git lfs pull
|
# git lfs pull
|
||||||
|
#
|
||||||
- name: Run tests
|
# - name: Run tests
|
||||||
uses: godot-gdunit-labs/gdUnit4-action@v1
|
# uses: godot-gdunit-labs/gdUnit4-action@v1
|
||||||
with:
|
# with:
|
||||||
godot-version: '4.6.0'
|
# godot-version: '4.6.0'
|
||||||
godot-net: true
|
# godot-net: true
|
||||||
godot-force-mono: true
|
# godot-force-mono: true
|
||||||
dotnet-version: 'net9.0'
|
# dotnet-version: 'net9.0'
|
||||||
paths: |
|
# paths: |
|
||||||
res://tests/
|
# res://tests/
|
||||||
timeout: 1
|
# timeout: 1
|
||||||
publish-report: false
|
# publish-report: false
|
||||||
upload-report: false
|
# upload-report: false
|
||||||
|
#
|
||||||
- name: Upload test report
|
# - name: Upload test report
|
||||||
uses: actions/upload-artifact@v3-node20
|
# uses: actions/upload-artifact@v3-node20
|
||||||
with:
|
# with:
|
||||||
name: Test Report
|
# name: Test Report
|
||||||
path: ${{ github.workspace }}/reports/test-result.html
|
# path: ${{ github.workspace }}/reports/test-result.html
|
||||||
|
|
||||||
Export:
|
Export:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -85,7 +85,7 @@ jobs:
|
|||||||
RUNNER_TOOL_CACHE: /toolcache # Runner Tool Cache
|
RUNNER_TOOL_CACHE: /toolcache # Runner Tool Cache
|
||||||
needs:
|
needs:
|
||||||
- BumpTag
|
- BumpTag
|
||||||
- Test # Wait for tests to finish
|
# - Test # Wait for tests to finish
|
||||||
container:
|
container:
|
||||||
image: barichello/godot-ci:mono-4.6
|
image: barichello/godot-ci:mono-4.6
|
||||||
|
|
||||||
@@ -95,24 +95,49 @@ jobs:
|
|||||||
apt update && apt -y install curl zip nodejs
|
apt update && apt -y install curl zip nodejs
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
lfs: false
|
lfs: false
|
||||||
persist-credentials: true
|
|
||||||
|
|
||||||
- name: Checkout LFS
|
- name: Checkout LFS
|
||||||
run: |
|
run: |
|
||||||
git lfs install --local
|
UrlBase=$GITHUB_SERVER_URL; \
|
||||||
AUTH=$(git config http.${{ gitea.server_url }}/.extraheader)
|
UrlLfsBase=$UrlBase/${{ gitea.repository }}.git/info/lfs/objects; \
|
||||||
AUTH_FILE=$(git config includeif.gitdir:/workspace/${{ gitea.repository }}/.git.path)
|
Auth=`/usr/bin/git config --get --local http.$UrlBase/.extraheader`; \
|
||||||
git config -f $AUTH_FILE --unset http.${{ gitea.server_url }}/.extraheader
|
/usr/bin/git config --local http.${UrlLfsBase}/batch.extraheader "$Auth"; \
|
||||||
git config -f $AUTH_FILE http.${{ gitea.server_url }}/${{ gitea.repository }}.git/info/lfs/objects/batch.extraheader "$AUTH"
|
/usr/bin/git config --local http.${UrlLfsBase}/.extraheader ''
|
||||||
git lfs pull
|
|
||||||
|
git config --local lfs.transfer.maxretries 1
|
||||||
|
|
||||||
|
/usr/bin/git lfs fetch origin refs/remotes/origin/${{ gitea.ref_name }}
|
||||||
|
/usr/bin/git lfs checkout
|
||||||
|
/usr/bin/git add .
|
||||||
|
/usr/bin/git reset --hard
|
||||||
|
|
||||||
|
# - name: Checkout
|
||||||
|
# uses: actions/checkout@v6
|
||||||
|
# with:
|
||||||
|
# lfs: false
|
||||||
|
# persist-credentials: true
|
||||||
|
#
|
||||||
|
# - name: Checkout LFS
|
||||||
|
# run: |
|
||||||
|
# git lfs install --local
|
||||||
|
# AUTH=$(git config http.${{ gitea.server_url }}/.extraheader)
|
||||||
|
# AUTH_FILE=$(git config includeif.gitdir:/workspace/${{ gitea.repository }}/.git.path)
|
||||||
|
# git config -f $AUTH_FILE --unset http.${{ gitea.server_url }}/.extraheader
|
||||||
|
# git config -f $AUTH_FILE http.${{ gitea.server_url }}/${{ gitea.repository }}.git/info/lfs/objects/batch.extraheader "$AUTH"
|
||||||
|
# git lfs pull
|
||||||
|
|
||||||
- name: Remove GDUnit addon folder because it breaks the build
|
- name: Remove GDUnit addon folder because it breaks the build
|
||||||
run: |
|
run: |
|
||||||
rm -rf ${{ gitea.workspace }}/addons/gdUnit4
|
rm -rf ${{ gitea.workspace }}/addons/gdUnit4
|
||||||
|
|
||||||
|
# Replacement while waiting for 4.6 support
|
||||||
|
- name: Import resources and build solution
|
||||||
|
run: |
|
||||||
|
godot --headless --editor --build-solutions --quit --import --path $PWD
|
||||||
|
|
||||||
- name: Build Windows
|
- name: Build Windows
|
||||||
run: |
|
run: |
|
||||||
mkdir -v -p build/windows
|
mkdir -v -p build/windows
|
||||||
|
|||||||
@@ -40,19 +40,24 @@ jobs:
|
|||||||
apt update && apt -y install curl zip nodejs
|
apt update && apt -y install curl zip nodejs
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
lfs: false
|
lfs: false
|
||||||
persist-credentials: true
|
|
||||||
|
|
||||||
- name: Checkout LFS
|
- name: Checkout LFS
|
||||||
run: |
|
run: |
|
||||||
git lfs install --local
|
UrlBase=$GITHUB_SERVER_URL; \
|
||||||
AUTH=$(git config http.${{ gitea.server_url }}/.extraheader)
|
UrlLfsBase=$UrlBase/${{ gitea.repository }}.git/info/lfs/objects; \
|
||||||
AUTH_FILE=$(git config includeif.gitdir:/workspace/${{ gitea.repository }}/.git.path)
|
Auth=`/usr/bin/git config --get --local http.$UrlBase/.extraheader`; \
|
||||||
git config -f $AUTH_FILE --unset http.${{ gitea.server_url }}/.extraheader
|
/usr/bin/git config --local http.${UrlLfsBase}/batch.extraheader "$Auth"; \
|
||||||
git config -f $AUTH_FILE http.${{ gitea.server_url }}/${{ gitea.repository }}.git/info/lfs/objects/batch.extraheader "$AUTH"
|
/usr/bin/git config --local http.${UrlLfsBase}/.extraheader ''
|
||||||
git lfs pull
|
|
||||||
|
git config --local lfs.transfer.maxretries 1
|
||||||
|
|
||||||
|
/usr/bin/git lfs fetch origin refs/remotes/origin/${{ gitea.ref_name }}
|
||||||
|
/usr/bin/git lfs checkout
|
||||||
|
/usr/bin/git add .
|
||||||
|
/usr/bin/git reset --hard
|
||||||
|
|
||||||
- name: Import resources and build solution
|
- name: Import resources and build solution
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace GodotStateCharts
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The wrapped node.
|
/// The wrapped node.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly Node Wrapped;
|
public readonly Node Wrapped;
|
||||||
|
|
||||||
protected NodeWrapper(Node wrapped)
|
protected NodeWrapper(Node wrapped)
|
||||||
{
|
{
|
||||||
|
|||||||
39
addons/godot_state_charts/csharp/ResourceWrapper.cs
Normal file
39
addons/godot_state_charts/csharp/ResourceWrapper.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// ReSharper disable once CheckNamespace
|
||||||
|
namespace GodotStateCharts
|
||||||
|
{
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for all wrapper classes for Godot Resource types. Provides common functionality. Not to be used directly.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class ResourceWrapper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The wrapped resource. Useful for you need to access the underlying resource directly,
|
||||||
|
/// e.g. for serialization.
|
||||||
|
/// </summary>
|
||||||
|
public readonly Resource Wrapped;
|
||||||
|
|
||||||
|
protected ResourceWrapper(Resource wrapped)
|
||||||
|
{
|
||||||
|
Wrapped = wrapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Allows to call methods on the wrapped resource deferred.
|
||||||
|
/// </summary>
|
||||||
|
public Variant CallDeferred(string method, params Variant[] args)
|
||||||
|
{
|
||||||
|
return Wrapped.CallDeferred(method, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Allows to call methods on the wrapped resource.
|
||||||
|
/// </summary>
|
||||||
|
public Variant Call(string method, params Variant[] args)
|
||||||
|
{
|
||||||
|
return Wrapped.Call(method, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
1
addons/godot_state_charts/csharp/ResourceWrapper.cs.uid
Normal file
1
addons/godot_state_charts/csharp/ResourceWrapper.cs.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://j8ro24kpswjd
|
||||||
89
addons/godot_state_charts/csharp/SerializedStateChart.cs
Normal file
89
addons/godot_state_charts/csharp/SerializedStateChart.cs
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
// ReSharper disable once CheckNamespace
|
||||||
|
namespace GodotStateCharts
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// C# wrapper for the SerializedStateChart Godot resource.
|
||||||
|
/// </summary>
|
||||||
|
public class SerializedStateChart : ResourceWrapper
|
||||||
|
{
|
||||||
|
private SerializedStateChart(Resource wrapped) : base(wrapped) { }
|
||||||
|
|
||||||
|
public static SerializedStateChart Of(Resource resource)
|
||||||
|
{
|
||||||
|
if (resource.GetScript().As<Script>() is not GDScript gdScript
|
||||||
|
|| !gdScript.ResourcePath.EndsWith("serialized_state_chart.gd"))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Given resource is not a SerializedStateChart.");
|
||||||
|
}
|
||||||
|
return new SerializedStateChart(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Version
|
||||||
|
{
|
||||||
|
get => Wrapped.Get("version").AsInt32();
|
||||||
|
set => Wrapped.Set("version", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get => Wrapped.Get("name").AsString();
|
||||||
|
set => Wrapped.Set("name", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Godot.Collections.Dictionary ExpressionProperties
|
||||||
|
{
|
||||||
|
get => Wrapped.Get("expression_properties").AsGodotDictionary();
|
||||||
|
set => Wrapped.Set("expression_properties", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Godot.Collections.Array QueuedEvents
|
||||||
|
{
|
||||||
|
get => Wrapped.Get("queued_events").AsGodotArray();
|
||||||
|
set => Wrapped.Set("queued_events", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool PropertyChangePending
|
||||||
|
{
|
||||||
|
get => Wrapped.Get("property_change_pending").AsBool();
|
||||||
|
set => Wrapped.Set("property_change_pending", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool StateChangePending
|
||||||
|
{
|
||||||
|
get => Wrapped.Get("state_change_pending").AsBool();
|
||||||
|
set => Wrapped.Set("state_change_pending", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool LockedDown
|
||||||
|
{
|
||||||
|
get => Wrapped.Get("locked_down").AsBool();
|
||||||
|
set => Wrapped.Set("locked_down", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Godot.Collections.Array QueuedTransitions
|
||||||
|
{
|
||||||
|
get => Wrapped.Get("queued_transitions").AsGodotArray();
|
||||||
|
set => Wrapped.Set("queued_transitions", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TransitionsProcessingActive
|
||||||
|
{
|
||||||
|
get => Wrapped.Get("transitions_processing_active").AsBool();
|
||||||
|
set => Wrapped.Set("transitions_processing_active", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SerializedStateChartState State
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var stateRes = Wrapped.Get("state").As<Resource>();
|
||||||
|
return stateRes != null ? SerializedStateChartState.Of(stateRes) : null;
|
||||||
|
}
|
||||||
|
set => Wrapped.Set("state", value?.Wrapped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://vsn1msuytiho
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace GodotStateCharts
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// C# wrapper for the SerializedStateChartState Godot resource.
|
||||||
|
/// </summary>
|
||||||
|
public class SerializedStateChartState : ResourceWrapper
|
||||||
|
{
|
||||||
|
private SerializedStateChartState(Resource wrapped) : base(wrapped)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SerializedStateChartState Of(Resource resource)
|
||||||
|
{
|
||||||
|
if (resource.GetScript().As<Script>() is not GDScript gdScript
|
||||||
|
|| !gdScript.ResourcePath.EndsWith("serialized_state_chart_state.gd"))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Given resource is not a SerializedStateChartState.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SerializedStateChartState(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get => Wrapped.Get("name").AsString();
|
||||||
|
set => Wrapped.Set("name", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int StateType
|
||||||
|
{
|
||||||
|
get => Wrapped.Get("state_type").AsInt32();
|
||||||
|
set => Wrapped.Set("state_type", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Active
|
||||||
|
{
|
||||||
|
get => Wrapped.Get("active").AsBool();
|
||||||
|
set => Wrapped.Set("active", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string PendingTransitionName
|
||||||
|
{
|
||||||
|
get => Wrapped.Get("pending_transition_name").AsString();
|
||||||
|
set => Wrapped.Set("pending_transition_name", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float PendingTransitionRemainingDelay
|
||||||
|
{
|
||||||
|
get => Wrapped.Get("pending_transition_remaining_delay").AsSingle();
|
||||||
|
set => Wrapped.Set("pending_transition_remaining_delay", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float PendingTransitionInitialDelay
|
||||||
|
{
|
||||||
|
get => Wrapped.Get("pending_transition_initial_delay").AsSingle();
|
||||||
|
set => Wrapped.Set("pending_transition_initial_delay", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SerializedStateChartState> Children
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var wrappedChildren = Wrapped.Get("children").AsGodotArray();
|
||||||
|
var result = new List<SerializedStateChartState>();
|
||||||
|
// ReSharper disable once LoopCanBeConvertedToQuery
|
||||||
|
foreach (var item in wrappedChildren)
|
||||||
|
{
|
||||||
|
result.Add(Of(item.As<Resource>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
var wrappedChildren = new Godot.Collections.Array();
|
||||||
|
foreach (var child in value)
|
||||||
|
{
|
||||||
|
wrappedChildren.Add(child.Wrapped);
|
||||||
|
}
|
||||||
|
|
||||||
|
Wrapped.Set("children", wrappedChildren);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://bxbsjxky868w0
|
||||||
32
addons/godot_state_charts/csharp/StateChartSerializer.cs
Normal file
32
addons/godot_state_charts/csharp/StateChartSerializer.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
namespace GodotStateCharts;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
public class StateChartSerializer
|
||||||
|
{
|
||||||
|
private static readonly GodotObject Wrapped = GD.Load("res://addons/godot_state_charts/state_chart_serializer.gd");
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Serializes the given state chart and returns a serialized object that
|
||||||
|
/// can be stored as part of a saved game.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stateChart">the state chart to serialize</param>
|
||||||
|
/// <returns>a resource containing the serialized state</returns>
|
||||||
|
public static SerializedStateChart Serialize(StateChart stateChart)
|
||||||
|
{
|
||||||
|
return SerializedStateChart.Of(Wrapped.Call("serialize", stateChart.Wrapped).As<Resource>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deserializes the given serialized state chart into the given state chart. Returns a set of
|
||||||
|
/// error messages. If the serialized state chart was no longer compatible with the current state
|
||||||
|
/// chart, nothing will happen. The operation is successful when the returned array is empty.
|
||||||
|
/// </summary>
|
||||||
|
public static string[] Deserialize(SerializedStateChart serializedStateChart, StateChart stateChart)
|
||||||
|
{
|
||||||
|
var variant = Wrapped.Call("deserialize", serializedStateChart.Wrapped, stateChart.Wrapped);
|
||||||
|
return variant.AsStringArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://cfttxxidmbax6
|
||||||
46
addons/godot_state_charts/serialized_state_chart.gd
Normal file
46
addons/godot_state_charts/serialized_state_chart.gd
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# This class is used to serialize a state chart to a resource. It is intended
|
||||||
|
# to make it easier to save and load state charts, as well as to transfer them
|
||||||
|
# over the network if needed.
|
||||||
|
#
|
||||||
|
# This class contains the state of the state chart, as well as the state of all
|
||||||
|
# its children.
|
||||||
|
class_name SerializedStateChart
|
||||||
|
extends Resource
|
||||||
|
|
||||||
|
## This is just in case we change the way this is serialized down the road,
|
||||||
|
## so we have a way of migrating.
|
||||||
|
@export var version:int = 1
|
||||||
|
@export var name: String = ""
|
||||||
|
@export var expression_properties: Dictionary = {}
|
||||||
|
@export var queued_events: Array[StringName] = []
|
||||||
|
@export var property_change_pending: bool = false
|
||||||
|
@export var state_change_pending: bool = false
|
||||||
|
@export var locked_down: bool = false
|
||||||
|
@export var queued_transitions: Array[Dictionary] = []
|
||||||
|
@export var transitions_processing_active: bool = false
|
||||||
|
@export var state: SerializedStateChartState = null
|
||||||
|
|
||||||
|
func _to_string() -> String:
|
||||||
|
return """SerializedStateChart(
|
||||||
|
version: %d
|
||||||
|
name: %s
|
||||||
|
expression_properties: %s
|
||||||
|
queued_events: %s
|
||||||
|
property_change_pending: %s
|
||||||
|
state_change_pending: %s
|
||||||
|
locked_down: %s
|
||||||
|
queued_transitions: %s
|
||||||
|
transitions_processing_active: %s
|
||||||
|
state: %s
|
||||||
|
)""" % [
|
||||||
|
version,
|
||||||
|
name,
|
||||||
|
JSON.stringify(expression_properties, "\t"),
|
||||||
|
JSON.stringify(queued_events, "\t"),
|
||||||
|
property_change_pending,
|
||||||
|
state_change_pending,
|
||||||
|
locked_down,
|
||||||
|
JSON.stringify(queued_transitions, "\t"),
|
||||||
|
transitions_processing_active,
|
||||||
|
state.debug_string() if state != null else "null"
|
||||||
|
]
|
||||||
1
addons/godot_state_charts/serialized_state_chart.gd.uid
Normal file
1
addons/godot_state_charts/serialized_state_chart.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://btjh2htgxjw8v
|
||||||
38
addons/godot_state_charts/serialized_state_chart_state.gd
Normal file
38
addons/godot_state_charts/serialized_state_chart_state.gd
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# This class is used to serialize a state chart state to a resource. It is intended
|
||||||
|
# to make it easier to save and load state charts, as well as to transfer them
|
||||||
|
# over the network if needed. See also SerializedStateChartResource.
|
||||||
|
class_name SerializedStateChartState
|
||||||
|
extends Resource
|
||||||
|
|
||||||
|
@export var name: StringName = ""
|
||||||
|
@export var state_type: int = -1
|
||||||
|
@export var active: bool = false
|
||||||
|
@export var pending_transition_name: String = ""
|
||||||
|
@export var pending_transition_remaining_delay: float = 0.0
|
||||||
|
@export var pending_transition_initial_delay: float = 0.0
|
||||||
|
@export var children: Array[SerializedStateChartState] = []
|
||||||
|
|
||||||
|
# Only used for history states
|
||||||
|
@export var history: SavedState = null
|
||||||
|
|
||||||
|
|
||||||
|
func _to_string() -> String:
|
||||||
|
return """SerializedStateChartState(
|
||||||
|
name: %s
|
||||||
|
state_class: %s
|
||||||
|
active: %s
|
||||||
|
pending_transition_name: %s
|
||||||
|
pending_transition_remaining_delay: %s
|
||||||
|
pending_transition_initial_delay: %s
|
||||||
|
children: %s
|
||||||
|
history: %s
|
||||||
|
)""" % [
|
||||||
|
name,
|
||||||
|
state_type,
|
||||||
|
active,
|
||||||
|
pending_transition_name,
|
||||||
|
pending_transition_remaining_delay,
|
||||||
|
pending_transition_initial_delay,
|
||||||
|
JSON.stringify(children, "\t"),
|
||||||
|
history.debug_string() if history != null else "null"
|
||||||
|
]
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://ckplopl15o5bb
|
||||||
193
addons/godot_state_charts/state_chart_serializer.gd
Normal file
193
addons/godot_state_charts/state_chart_serializer.gd
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
## Helper class for serializing and deserializing state charts.
|
||||||
|
class_name StateChartSerializer
|
||||||
|
|
||||||
|
## Serializes the given state chart and returns a serialized object that
|
||||||
|
## can be stored as part of a saved game.
|
||||||
|
static func serialize(state_chart: StateChart) -> SerializedStateChart:
|
||||||
|
state_chart.freeze()
|
||||||
|
var result := _serialize_chart(state_chart)
|
||||||
|
state_chart.thaw()
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
## Deserializes the given serialized state chart into the given state chart. Returns a set of
|
||||||
|
## error messages. If the serialized state chart was no longer compatible with the current state
|
||||||
|
## chart, nothing will happen. The operation is successful when the returned array is emtpy.
|
||||||
|
static func deserialize(serialized_state_chart: SerializedStateChart, state_chart: StateChart) -> PackedStringArray:
|
||||||
|
var error_messages: PackedStringArray = []
|
||||||
|
_verify_chart_compatibility(serialized_state_chart, state_chart, error_messages)
|
||||||
|
if not error_messages.is_empty():
|
||||||
|
return error_messages
|
||||||
|
|
||||||
|
state_chart.freeze()
|
||||||
|
_deserialize_chart(serialized_state_chart, state_chart)
|
||||||
|
state_chart.thaw()
|
||||||
|
|
||||||
|
state_chart._run_queued_transitions()
|
||||||
|
state_chart._run_changes()
|
||||||
|
|
||||||
|
return error_messages
|
||||||
|
|
||||||
|
|
||||||
|
## Recursively builds a Resource representation of this state chart and it's children.
|
||||||
|
## This function is intended to be used for serializing into the desired format (such as a file or JSON)
|
||||||
|
## as needed for game saves or network transmission.
|
||||||
|
## This method assumes that the StateChart will be constructed and added to the tree prior
|
||||||
|
## to loading the resource. As such, it does not store data, such as Transitions, which will be
|
||||||
|
## created in the Node Tree.
|
||||||
|
static func _serialize_chart(state_chart: StateChart) -> SerializedStateChart:
|
||||||
|
assert(state_chart != null, "tried to serialize a null chart.")
|
||||||
|
|
||||||
|
var result: SerializedStateChart = SerializedStateChart.new()
|
||||||
|
result.name = state_chart.name
|
||||||
|
result.expression_properties = state_chart._expression_properties
|
||||||
|
result.queued_events = state_chart._queued_events
|
||||||
|
result.property_change_pending = state_chart._property_change_pending
|
||||||
|
result.state_change_pending = state_chart._state_change_pending
|
||||||
|
result.locked_down = state_chart._locked_down
|
||||||
|
result.queued_transitions = state_chart._queued_transitions
|
||||||
|
result.transitions_processing_active = state_chart._transitions_processing_active
|
||||||
|
result.state = _serialize_state(state_chart._state)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
## Loads a state chart from a resource. This will replace the current state chart's internal state with the one in the resource.
|
||||||
|
## Events and transitions will not be processed or queued during the load process.
|
||||||
|
## Loading assumes that the state chart states have already been instantiated into your node tree. This will
|
||||||
|
## update existing nodes in the tree, but not create new nodes that do not yet exist. Data for non-existent nodes
|
||||||
|
## will be discarded. If you want to create new nodes, you need to do so manually from the resource objects prior
|
||||||
|
## to calling this method.
|
||||||
|
static func _deserialize_chart(serialized_chart: SerializedStateChart, target: StateChart) -> void:
|
||||||
|
assert(serialized_chart != null, "tried to deserialize a null serialized state chart.")
|
||||||
|
assert(target != null, "tried to deserialize into a null state chart.")
|
||||||
|
|
||||||
|
# load the state chart data
|
||||||
|
target._expression_properties = serialized_chart.expression_properties
|
||||||
|
target._queued_events = serialized_chart.queued_events
|
||||||
|
target._property_change_pending = serialized_chart.property_change_pending
|
||||||
|
target._state_change_pending = serialized_chart.state_change_pending
|
||||||
|
target._locked_down = serialized_chart.locked_down
|
||||||
|
target._queued_transitions = serialized_chart.queued_transitions
|
||||||
|
target._transitions_processing_active = serialized_chart.transitions_processing_active
|
||||||
|
|
||||||
|
# and all the states
|
||||||
|
_deserialize_state(serialized_chart.state, target._state)
|
||||||
|
|
||||||
|
|
||||||
|
## Serializes the given state chart state into a serialized state chart state.
|
||||||
|
static func _serialize_state(state: StateChartState) -> SerializedStateChartState:
|
||||||
|
assert(state != null, "tried to serialize a null state.")
|
||||||
|
var result := SerializedStateChartState.new()
|
||||||
|
result.name = state.name
|
||||||
|
result.state_type = _type_for_state(state)
|
||||||
|
result.active = state._state_active
|
||||||
|
result.pending_transition_name = state._pending_transition.name if state._pending_transition != null else ""
|
||||||
|
result.pending_transition_remaining_delay = state._pending_transition_remaining_delay
|
||||||
|
result.pending_transition_initial_delay = state._pending_transition_initial_delay
|
||||||
|
if state is HistoryState:
|
||||||
|
result.history = state.history
|
||||||
|
|
||||||
|
result.children = []
|
||||||
|
|
||||||
|
for child in state.get_children():
|
||||||
|
if child is StateChartState:
|
||||||
|
result.children.append(_serialize_state(child))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
## Deserializes a serialized state chart state into a state chart state.
|
||||||
|
static func _deserialize_state(serialized_state: SerializedStateChartState, target: StateChartState) -> void:
|
||||||
|
assert(serialized_state != null, "tried to deserialize a null serialized state.")
|
||||||
|
assert(target != null, "tried to deserialize into a null state.")
|
||||||
|
|
||||||
|
target._state_active = serialized_state.active
|
||||||
|
|
||||||
|
if serialized_state.pending_transition_name != "":
|
||||||
|
target._pending_transition = target.get_node(serialized_state.pending_transition_name)
|
||||||
|
else:
|
||||||
|
target._pending_transition = null
|
||||||
|
|
||||||
|
target._pending_transition_remaining_delay = serialized_state.pending_transition_remaining_delay
|
||||||
|
target._pending_transition_initial_delay = serialized_state.pending_transition_initial_delay
|
||||||
|
if target is HistoryState:
|
||||||
|
target.history = serialized_state.history
|
||||||
|
|
||||||
|
for child_serialized_state in serialized_state.children:
|
||||||
|
var child_state: StateChartState = target.get_node(NodePath(child_serialized_state.name))
|
||||||
|
_deserialize_state(child_serialized_state, child_state)
|
||||||
|
|
||||||
|
if target is CompoundState:
|
||||||
|
# ensure _active_state is set to the currently active child
|
||||||
|
if target._state_active:
|
||||||
|
# find the currently active child
|
||||||
|
for child in target.get_children():
|
||||||
|
if child is StateChartState and child._state_active:
|
||||||
|
target._active_state = child
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
## Verify that the serialized state chart can actually be restored on the target state chart.
|
||||||
|
static func _verify_chart_compatibility(serialized_state_chart: SerializedStateChart, target: StateChart, error_messages: PackedStringArray) -> void:
|
||||||
|
var message_prefix: String = "[%s]:" % [target.get_path()]
|
||||||
|
if serialized_state_chart.version != 1:
|
||||||
|
error_messages.append("%s Unsupported serialized state chart version %s != %s." % [message_prefix, serialized_state_chart.version, 1])
|
||||||
|
|
||||||
|
_verify_state_compatiblity(serialized_state_chart.state, target._state, error_messages)
|
||||||
|
|
||||||
|
|
||||||
|
## Checks if the given serialized state can be restored on the given state.
|
||||||
|
static func _verify_state_compatiblity(serialized_state: SerializedStateChartState, target: StateChartState, error_messages: PackedStringArray) -> void:
|
||||||
|
var message_prefix: String = "[%s]:" % [_get_state_path(target)]
|
||||||
|
|
||||||
|
if serialized_state.name != target.name:
|
||||||
|
error_messages.append("%s State name mismatch: %s != %s" % [message_prefix, target.name, serialized_state.name])
|
||||||
|
|
||||||
|
if serialized_state.state_type != _type_for_state(target):
|
||||||
|
error_messages.append("%s State type mismatch: %s != %s " % [message_prefix, _type_for_state(target), serialized_state.state_type])
|
||||||
|
|
||||||
|
if not serialized_state.pending_transition_name.is_empty() \
|
||||||
|
and target.get_node_or_null(serialized_state.pending_transition_name) == null:
|
||||||
|
error_messages.append("%s Pending transition %s not found" % [message_prefix, serialized_state.pending_transition_name])
|
||||||
|
|
||||||
|
var states_in_tree: Array[StringName] = []
|
||||||
|
|
||||||
|
var states_in_serialized_version: Array[StringName] = []
|
||||||
|
|
||||||
|
for child in target.get_children():
|
||||||
|
if child is StateChartState:
|
||||||
|
states_in_tree.append(child.name)
|
||||||
|
|
||||||
|
for serialized_child in serialized_state.children:
|
||||||
|
states_in_serialized_version.append(serialized_child.name)
|
||||||
|
|
||||||
|
var child: Node = target.get_node_or_null(NodePath(serialized_child.name))
|
||||||
|
if child == null:
|
||||||
|
error_messages.append("%s Serialized state has child state %s but no such state exists in the tree." % [message_prefix, serialized_child.name])
|
||||||
|
else:
|
||||||
|
_verify_state_compatiblity(serialized_child, child, error_messages)
|
||||||
|
|
||||||
|
var in_tree_but_missing_in_serialized: Array = states_in_tree.filter(func(it): return not states_in_serialized_version.has(it))
|
||||||
|
for item in in_tree_but_missing_in_serialized:
|
||||||
|
error_messages.append("%s Tree has child state %s but no such child state exists in the serialized state." % [message_prefix, str(item)])
|
||||||
|
|
||||||
|
|
||||||
|
## Returns an integer giving the state type.
|
||||||
|
static func _type_for_state(state: StateChartState) -> int:
|
||||||
|
if state is AtomicState:
|
||||||
|
return 0
|
||||||
|
if state is CompoundState:
|
||||||
|
return 1
|
||||||
|
if state is ParallelState:
|
||||||
|
return 2
|
||||||
|
if state is HistoryState:
|
||||||
|
return 3
|
||||||
|
assert(false, "Unknown state type")
|
||||||
|
return -1
|
||||||
|
|
||||||
|
|
||||||
|
## Returns the path from the state's chart to the state.
|
||||||
|
static func _get_state_path(state: StateChartState) -> String:
|
||||||
|
if state == null or state._chart == null:
|
||||||
|
return ""
|
||||||
|
return str(state._chart.get_path_to(state))
|
||||||
1
addons/godot_state_charts/state_chart_serializer.gd.uid
Normal file
1
addons/godot_state_charts/state_chart_serializer.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://b0dtst4p1bter
|
||||||
Reference in New Issue
Block a user