Skip to content

Commit 8170798

Browse files
committed
gle: Fix state notifications.
1 parent 4fcd889 commit 8170798

11 files changed

+135
-17
lines changed

Editor/Descriptors/CreatePlayerStateUnitDescriptor.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ protected override void DefinedPort(IUnitPort port, UnitPortDescription desc)
4848
case nameof(CreatePlayerStateUnit.SetAsActive):
4949
desc.summary = "If set, the new state will be the current state. Otherwise, it will only be the current state if there is no state set.";
5050
break;
51+
case nameof(CreatePlayerStateUnit.DestroyPrevious):
52+
desc.summary = "If set, all player states are destroyed before creating a new one. This is typically used when starting the first ball.";
53+
break;
5154
}
5255
}
5356
}

Editor/Descriptors/IncreaseVariableUnitDescriptor.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ protected override void DefinedPort(IUnitPort port, UnitPortDescription desc)
4242
case nameof(IncreasePlayerVariableUnit.Value):
4343
desc.summary = "The value to add to the existing value.";
4444
break;
45+
case nameof(IncreasePlayerVariableUnit.OutputValue):
46+
desc.summary = "The final increased value.";
47+
break;
4548
}
4649
}
4750
}
@@ -68,6 +71,9 @@ protected override void DefinedPort(IUnitPort port, UnitPortDescription desc)
6871
case nameof(IncreaseTableVariableUnit.Value):
6972
desc.summary = "The value to add to the existing value.";
7073
break;
74+
case nameof(IncreasePlayerVariableUnit.OutputValue):
75+
desc.summary = "The final increased value.";
76+
break;
7177
}
7278
}
7379
}

Editor/Descriptors/SetVariableUnitDescriptor.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ protected override void DefinedPort(IUnitPort port, UnitPortDescription desc)
4242
case nameof(SetPlayerVariableUnit.Value):
4343
desc.summary = "The new value of the player variable.";
4444
break;
45+
case nameof(SetPlayerVariableUnit.OutputValue):
46+
desc.summary = "The new value of the player variable.";
47+
break;
4548
}
4649
}
4750
}
@@ -68,6 +71,10 @@ protected override void DefinedPort(IUnitPort port, UnitPortDescription desc)
6871
case nameof(SetTableVariableUnit.Value):
6972
desc.summary = "The new value of the table variable.";
7073
break;
74+
75+
case nameof(SetTableVariableUnit.OutputValue):
76+
desc.summary = "The new value of the table variable.";
77+
break;
7178
}
7279
}
7380
}

Editor/Widgets/GetSwitchUnitWidget.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public override Inspector GetPortInspector(IUnitPort port, Metadata meta)
5050
}
5151
}
5252

53+
5354
return base.GetPortInspector(port, meta);
5455
}
5556

Runtime/Gamelogic/State.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ public T Get<T>(string variableId) where T : class
6161
return _variables[variableId].Get<T>();
6262
}
6363

64+
public StateVariable GetVariable(string variableId) => _variables[variableId];
65+
6466
public object Get(string variableId)
6567
{
6668
if (!_variables.ContainsKey(variableId)) {

Runtime/Gamelogic/StateVariable.cs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
namespace VisualPinball.Unity.VisualScripting
2020
{
21-
public class StateVariable
21+
public class StateVariable : IEquatable<StateVariable>
2222
{
2323
public string Id;
2424
public string Name;
@@ -55,5 +55,50 @@ public void Set<T>(T value)
5555
{
5656
_value = value;
5757
}
58+
59+
public bool Equals(StateVariable other)
60+
{
61+
if (ReferenceEquals(null, other)) {
62+
return false;
63+
}
64+
if (ReferenceEquals(this, other)) {
65+
return true;
66+
}
67+
68+
if (other.Type != Type) {
69+
return false;
70+
}
71+
72+
if (Type == typeof(string)) {
73+
return string.Equals(_value as string, other._value as string);
74+
}
75+
if (Type == typeof(int)) {
76+
return (int)_value == (int)other._value;
77+
}
78+
if (Type == typeof(float)) {
79+
return (float)_value == (float)other._value;
80+
}
81+
if (Type == typeof(bool)) {
82+
return (bool)_value == (bool)other._value;
83+
}
84+
return false;
85+
}
86+
87+
public override bool Equals(object obj) => Equals(obj as StateVariable);
88+
89+
public override int GetHashCode()
90+
{
91+
return (Id, Name, Type, _value).GetHashCode();
92+
}
93+
94+
public static bool operator ==(StateVariable lhs, StateVariable rhs)
95+
{
96+
if (lhs is null) {
97+
return rhs is null;
98+
}
99+
return lhs.Equals(rhs);
100+
}
101+
102+
public static bool operator !=(StateVariable lhs, StateVariable rhs) => !(lhs == rhs);
58103
}
59104
}

Runtime/Gamelogic/VisualScriptingGamelogicEngine.cs

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -80,17 +80,29 @@ public PlayerState CurrentPlayerState {
8080
}
8181
}
8282

83-
public int CurrentPlayer {
84-
get => _currentPlayer;
85-
set {
86-
if (!PlayerStates.ContainsKey(value)) {
87-
Debug.LogError($"Cannot change to non-existing player {value}.");
88-
return;
89-
}
90-
var previousPlayer = _currentPlayer;
91-
_currentPlayer = value;
92-
if (previousPlayer != _currentPlayer) {
93-
EventBus.Trigger(VisualScriptingEventNames.CurrentPlayerChanged, EventArgs.Empty);
83+
public void SetCurrentPlayer(int value, bool forceNotify = false)
84+
{
85+
if (!PlayerStates.ContainsKey(value)) {
86+
Debug.LogError($"Cannot change to non-existing player {value}.");
87+
return;
88+
}
89+
var previousPlayer = _currentPlayer;
90+
_currentPlayer = value;
91+
if (forceNotify || previousPlayer != _currentPlayer) {
92+
EventBus.Trigger(VisualScriptingEventNames.CurrentPlayerChanged, EventArgs.Empty);
93+
}
94+
95+
// also trigger updates for each variable
96+
foreach (var varDef in PlayerVariableDefinitions) {
97+
if (PlayerStates.ContainsKey(previousPlayer)) {
98+
var before = PlayerStates[previousPlayer].GetVariable(varDef.Id);
99+
var now = PlayerStates[_currentPlayer].GetVariable(varDef.Id);
100+
if (forceNotify || before != now) {
101+
EventBus.Trigger(VisualScriptingEventNames.PlayerVariableChanged, new VariableChangedArgs(varDef.Id));
102+
}
103+
104+
} else {
105+
EventBus.Trigger(VisualScriptingEventNames.PlayerVariableChanged, new VariableChangedArgs(varDef.Id));
94106
}
95107
}
96108
}
@@ -109,10 +121,16 @@ public void CreatePlayerState(int playerId)
109121

110122
// switch to this state if current state is invalid
111123
if (!PlayerStates.ContainsKey(_currentPlayer)) {
112-
CurrentPlayer = playerId;
124+
SetCurrentPlayer(playerId, true);
113125
}
114126
}
115127

128+
public void DestroyPlayerStates()
129+
{
130+
PlayerStates.Clear();
131+
_currentPlayer = 0;
132+
}
133+
116134
public void OnInit(Player player, TableApi tableApi, BallManager ballManager)
117135
{
118136
_player = player;
@@ -191,3 +209,4 @@ public void OnAfterDeserialize()
191209
}
192210
}
193211
}
212+

Runtime/Nodes/PlayerState/ChangePlayerStateUnit.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ private ControlOutput Process(Flow flow)
5454
throw new InvalidOperationException("Cannot retrieve GLE from unit.");
5555
}
5656

57-
VsGle.CurrentPlayer = flow.GetValue<int>(PlayerId);
57+
VsGle.SetCurrentPlayer(flow.GetValue<int>(PlayerId));
5858

5959
return OutputTrigger;
6060
}

Runtime/Nodes/PlayerState/CreatePlayerStateUnit.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ public class CreatePlayerStateUnit : GleUnit
4444
[PortLabel("Set as Active")]
4545
public ValueInput SetAsActive { get; set; }
4646

47+
[DoNotSerialize]
48+
[PortLabel("Destroy Previous")]
49+
public ValueInput DestroyPrevious { get; set; }
50+
4751
protected override void Definition()
4852
{
4953
InputTrigger = ControlInput(nameof(InputTrigger), Process);
@@ -55,6 +59,7 @@ protected override void Definition()
5559
}
5660

5761
SetAsActive = ValueInput(nameof(SetAsActive), false);
62+
DestroyPrevious = ValueInput(nameof(DestroyPrevious), false);
5863

5964
Succession(InputTrigger, OutputTrigger);
6065
}
@@ -65,6 +70,11 @@ private ControlOutput Process(Flow flow)
6570
throw new InvalidOperationException("Cannot retrieve GLE from unit.");
6671
}
6772

73+
// destroy previous
74+
if (flow.GetValue<bool>(DestroyPrevious)) {
75+
VsGle.DestroyPlayerStates();
76+
}
77+
6878
// determine new player id
6979
var newPlayerId = AutoIncrement && VsGle.PlayerStates.Count > 0
7080
? VsGle.PlayerStates.Keys.Max() + 1
@@ -75,7 +85,7 @@ private ControlOutput Process(Flow flow)
7585

7686
// set as active
7787
if (flow.GetValue<bool>(SetAsActive)) {
78-
VsGle.CurrentPlayer = newPlayerId;
88+
VsGle.SetCurrentPlayer(newPlayerId, flow.GetValue<bool>(DestroyPrevious));
7989
}
8090

8191
return OutputTrigger;

Runtime/Nodes/PlayerState/IncreaseVariableUnit.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,12 @@ public abstract class IncreaseVariableUnit : GleUnit
5151
[DoNotSerialize, PortLabelHidden]
5252
public ControlOutput OutputTrigger;
5353

54-
55-
[DoNotSerialize, PortLabel("Value"), Inspectable]
54+
[DoNotSerialize, PortLabel("Increase By"), Inspectable]
5655
public ValueInput Value { get; private set; }
5756

57+
[DoNotSerialize, PortLabel("Updated Value"), Inspectable]
58+
public ValueOutput OutputValue { get; private set; }
59+
5860
protected abstract State State { get; }
5961
protected abstract VariableDefinition VariableDefinition { get; }
6062

@@ -74,6 +76,12 @@ protected override void Definition()
7476
VariableType.Float => ValueInput<float>(nameof(Value), 0f),
7577
_ => throw new ArgumentOutOfRangeException($"Type must be integer or float.")
7678
};
79+
80+
OutputValue = VariableDefinition.Type switch {
81+
VariableType.Integer => ValueOutput<int>(nameof(Value)),
82+
VariableType.Float => ValueOutput<float>(nameof(Value)),
83+
_ => throw new ArgumentOutOfRangeException($"Type must be integer or float.")
84+
};
7785
Requirement(Value, InputTrigger);
7886
}
7987

@@ -87,11 +95,13 @@ private ControlOutput Process(Flow flow)
8795
case VariableType.Integer: {
8896
var current = (int)State.Get<Integer>(VariableDefinition.Id);
8997
State.Set(VariableDefinition.Id, new Integer(current + flow.GetValue<int>(Value)));
98+
flow.SetValue(OutputValue, current + flow.GetValue<int>(Value));
9099
break;
91100
}
92101
case VariableType.Float: {
93102
var current = (float)State.Get<Float>(VariableDefinition.Id);
94103
State.Set(VariableDefinition.Id, new Float(current + flow.GetValue<float>(Value)));
104+
flow.SetValue(OutputValue, current + flow.GetValue<float>(Value));
95105
break;
96106
}
97107
default:

0 commit comments

Comments
 (0)