diff --git a/Editor/Descriptors/AllCoilsEnabledEventUnitDescriptor.cs b/Editor/Descriptors/AllCoilsEnabledEventUnitDescriptor.cs new file mode 100644 index 0000000..6bd4ad4 --- /dev/null +++ b/Editor/Descriptors/AllCoilsEnabledEventUnitDescriptor.cs @@ -0,0 +1,32 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Descriptor(typeof(AllCoilsEnabledEventUnit))] + public class AllCoilsEnabledEventUnitDescriptor : MultiUnitDescriptor + { + public AllCoilsEnabledEventUnitDescriptor(AllCoilsEnabledEventUnit target) : base(target) { } + protected override string ItemLabel(int id) => $"Coil ID {id}"; + protected override string ItemDescription(int id) => $"Coil ID {id} to look for enabled status."; + protected override string DefinedSummary() => "This node triggers an event when the last coil in the list gets enabled."; + protected override EditorTexture DefinedIcon() => EditorTexture.Single(Unity.Editor.Icons.CoilEvent); + } +} diff --git a/Editor/Widgets/SetLightSequenceUnitWidget.cs.meta b/Editor/Descriptors/AllCoilsEnabledEventUnitDescriptor.cs.meta similarity index 83% rename from Editor/Widgets/SetLightSequenceUnitWidget.cs.meta rename to Editor/Descriptors/AllCoilsEnabledEventUnitDescriptor.cs.meta index 976ea63..92e11a4 100644 --- a/Editor/Widgets/SetLightSequenceUnitWidget.cs.meta +++ b/Editor/Descriptors/AllCoilsEnabledEventUnitDescriptor.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: e14ec4f39993ef2418a0309406658899 +guid: 9c90e18403ab74304aa29615cd8ac11b MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Editor/Descriptors/AllSwitchesEnabledEventUnitDescriptor.cs b/Editor/Descriptors/AllSwitchesEnabledEventUnitDescriptor.cs new file mode 100644 index 0000000..9a48155 --- /dev/null +++ b/Editor/Descriptors/AllSwitchesEnabledEventUnitDescriptor.cs @@ -0,0 +1,32 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Descriptor(typeof(AllSwitchesEnabledEventUnit))] + public class AllSwitchesEnabledEventUnitDescriptor : MultiUnitDescriptor + { + public AllSwitchesEnabledEventUnitDescriptor(AllSwitchesEnabledEventUnit target) : base(target) { } + protected override string ItemLabel(int id) => $"Switch ID {id}"; + protected override string ItemDescription(int id) => $"Switch ID {id} to look for enabled status."; + protected override string DefinedSummary() => "This node triggers an event when the last switch in the list gets enabled."; + protected override EditorTexture DefinedIcon() => EditorTexture.Single(Unity.Editor.Icons.SwitchEvent); + } +} diff --git a/Editor/Descriptors/SetLightSequenceUnitDescriptor.cs.meta b/Editor/Descriptors/AllSwitchesEnabledEventUnitDescriptor.cs.meta similarity index 83% rename from Editor/Descriptors/SetLightSequenceUnitDescriptor.cs.meta rename to Editor/Descriptors/AllSwitchesEnabledEventUnitDescriptor.cs.meta index 07d188a..fe57f10 100644 --- a/Editor/Descriptors/SetLightSequenceUnitDescriptor.cs.meta +++ b/Editor/Descriptors/AllSwitchesEnabledEventUnitDescriptor.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 7b4ee905eeb80ec48946a1fa5cdfe58b +guid: 50e4a21f16b43417c874257c215d8611 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Editor/Descriptors/ChangePlayerStateUnitDescriptor.cs b/Editor/Descriptors/ChangePlayerStateUnitDescriptor.cs new file mode 100644 index 0000000..d6c3343 --- /dev/null +++ b/Editor/Descriptors/ChangePlayerStateUnitDescriptor.cs @@ -0,0 +1,48 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Descriptor(typeof(ChangePlayerStateUnit))] + public class ChangePlayerStateUnitDescriptor : UnitDescriptor + { + public ChangePlayerStateUnitDescriptor(ChangePlayerStateUnit target) : base(target) + { + } + + protected override string DefinedSummary() + { + return "This node changes the current player state with another one."; + } + + protected override EditorTexture DefinedIcon() => EditorTexture.Single(Unity.Editor.Icons.PlayerVariable); + + protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) + { + base.DefinedPort(port, desc); + + switch (port.key) { + case nameof(ChangePlayerStateUnit.PlayerId): + desc.summary = "The player ID of the desired state"; + break; + } + } + } +} diff --git a/Editor/Widgets/SetLightUnitWidget.cs.meta b/Editor/Descriptors/ChangePlayerStateUnitDescriptor.cs.meta similarity index 83% rename from Editor/Widgets/SetLightUnitWidget.cs.meta rename to Editor/Descriptors/ChangePlayerStateUnitDescriptor.cs.meta index 6b81dce..09268f7 100644 --- a/Editor/Widgets/SetLightUnitWidget.cs.meta +++ b/Editor/Descriptors/ChangePlayerStateUnitDescriptor.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 7df567d7db6847548a21f012b1118cd2 +guid: 77a8b54096b355b45a2c1f19644007d8 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Editor/Descriptors/CoilEnabledEventUnitDescriptor.cs b/Editor/Descriptors/CoilEnabledEventUnitDescriptor.cs new file mode 100644 index 0000000..28c305f --- /dev/null +++ b/Editor/Descriptors/CoilEnabledEventUnitDescriptor.cs @@ -0,0 +1,49 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Descriptor(typeof(CoilEnabledEventUnit))] + public class CoilEnabledEventUnitDescriptor : UnitDescriptor + { + public CoilEnabledEventUnitDescriptor(CoilEnabledEventUnit target) : base(target) + { + } + + protected override string DefinedSummary() + { + return "This node triggers an event when a coil in the list of given ID is enabled."; + } + + protected override EditorTexture DefinedIcon() => EditorTexture.Single(Unity.Editor.Icons.CoilEvent); + + protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) + { + base.DefinedPort(port, desc); + + if (int.TryParse(port.key, out int id)) { + id += 1; + + desc.label = $"Coil ID {id}"; + desc.summary = $"Coil ID {id} to look for enabled status."; + } + } + } +} diff --git a/Editor/Descriptors/SetLightUnitDescriptor.cs.meta b/Editor/Descriptors/CoilEnabledEventUnitDescriptor.cs.meta similarity index 83% rename from Editor/Descriptors/SetLightUnitDescriptor.cs.meta rename to Editor/Descriptors/CoilEnabledEventUnitDescriptor.cs.meta index a685b04..554b7ca 100644 --- a/Editor/Descriptors/SetLightUnitDescriptor.cs.meta +++ b/Editor/Descriptors/CoilEnabledEventUnitDescriptor.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: e56287af571309349a1ef10db3293889 +guid: 9c0c89fb9024c456ab5414fb807087e0 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Editor/Descriptors/CoilEventUnitDescriptor.cs b/Editor/Descriptors/CoilEventUnitDescriptor.cs new file mode 100644 index 0000000..333f22d --- /dev/null +++ b/Editor/Descriptors/CoilEventUnitDescriptor.cs @@ -0,0 +1,52 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Descriptor(typeof(CoilEventUnit))] + public class CoilEventUnitDescriptor : UnitDescriptor + { + public CoilEventUnitDescriptor(CoilEventUnit target) : base(target) + { + } + + protected override string DefinedSummary() + { + return "This node triggers an event when a coil with a given ID changes."; + } + + protected override EditorTexture DefinedIcon() => EditorTexture.Single(Unity.Editor.Icons.CoilEvent); + + protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) + { + base.DefinedPort(port, desc); + + if (port.key == nameof(CoilEventUnit.IsEnabled)) { + desc.summary = "The new value of the coil, true if enabled, false otherwise."; + } + else if (int.TryParse(port.key, out int id)) { + id += 1; + + desc.label = $"Coil ID {id}"; + desc.summary = $"Coil ID {id} to look for a change status."; + } + } + } +} diff --git a/Editor/Descriptors/CoilEventUnitDescriptor.cs.meta b/Editor/Descriptors/CoilEventUnitDescriptor.cs.meta new file mode 100644 index 0000000..d9ef1f8 --- /dev/null +++ b/Editor/Descriptors/CoilEventUnitDescriptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: df01ed8be8c054d5c93bc9d392dc2d55 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Descriptors/CreatePlayerStateUnitDescriptor.cs b/Editor/Descriptors/CreatePlayerStateUnitDescriptor.cs new file mode 100644 index 0000000..f87522d --- /dev/null +++ b/Editor/Descriptors/CreatePlayerStateUnitDescriptor.cs @@ -0,0 +1,57 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Descriptor(typeof(CreatePlayerStateUnit))] + public class CreatePlayerStateUnitDescriptor : UnitDescriptor + { + public CreatePlayerStateUnitDescriptor(CreatePlayerStateUnit target) : base(target) + { + } + + protected override string DefinedSummary() + { + return "This node creates a new player state."; + } + + protected override EditorTexture DefinedIcon() => EditorTexture.Single(Unity.Editor.Icons.PlayerVariable); + + protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) + { + base.DefinedPort(port, desc); + + switch (port.key) { + case nameof(CreatePlayerStateUnit.PlayerId): + desc.summary = "The player ID of the new state"; + break; + // case nameof(PlayerStateCreateUnit.AutoIncrement): + // desc.summary = "If set, the new player ID will be the currently largest ID, plus one."; + // break; + case nameof(CreatePlayerStateUnit.SetAsActive): + 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."; + break; + case nameof(CreatePlayerStateUnit.DestroyPrevious): + desc.summary = "If set, all player states are destroyed before creating a new one. This is typically used when starting the first ball."; + break; + } + } + } +} diff --git a/Editor/Descriptors/CreatePlayerStateUnitDescriptor.cs.meta b/Editor/Descriptors/CreatePlayerStateUnitDescriptor.cs.meta new file mode 100644 index 0000000..ce0a62f --- /dev/null +++ b/Editor/Descriptors/CreatePlayerStateUnitDescriptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a0cab1524e6146a48ac09dc7694e6b25 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Descriptors/GetCoilUnitDescriptor.cs b/Editor/Descriptors/GetCoilUnitDescriptor.cs new file mode 100644 index 0000000..5968731 --- /dev/null +++ b/Editor/Descriptors/GetCoilUnitDescriptor.cs @@ -0,0 +1,53 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; +using VisualPinball.Unity.Editor; +using IconSize = VisualPinball.Unity.Editor.IconSize; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Descriptor(typeof(GetCoilUnit))] + public class GetCoilUnitDescriptor : UnitDescriptor + { + public GetCoilUnitDescriptor(GetCoilUnit target) : base(target) + { + } + + protected override string DefinedSummary() + { + return "This node retrieves the current status of the coil."; + } + + protected override EditorTexture DefinedIcon() => EditorTexture.Single(Unity.Editor.Icons.Coil(IconSize.Large, IconColor.Orange)); + + protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) + { + base.DefinedPort(port, desc); + + switch (port.key) { + case nameof(GetCoilUnit.Id): + desc.summary = "Coil ID to check if enabled."; + break; + case nameof(GetCoilUnit.IsEnabled): + desc.summary = "Whether the coil is enabled."; + break; + } + } + } +} diff --git a/Editor/Descriptors/GetCoilUnitDescriptor.cs.meta b/Editor/Descriptors/GetCoilUnitDescriptor.cs.meta new file mode 100644 index 0000000..ac5382c --- /dev/null +++ b/Editor/Descriptors/GetCoilUnitDescriptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5bff9c66ee0334b939db93256176fd40 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Descriptors/GetLampUnitDescriptor.cs b/Editor/Descriptors/GetLampUnitDescriptor.cs index 1361299..96a967e 100644 --- a/Editor/Descriptors/GetLampUnitDescriptor.cs +++ b/Editor/Descriptors/GetLampUnitDescriptor.cs @@ -16,6 +16,7 @@ // ReSharper disable UnusedType.Global +using System; using Unity.VisualScripting; using VisualPinball.Unity.Editor; using IconSize = VisualPinball.Unity.Editor.IconSize; @@ -45,10 +46,27 @@ protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) desc.summary = "The ID of the lamp for which the intensity is returned."; break; case nameof(GetLampUnit.Value): - desc.summary = "The intensity of the lamp (0-1)."; - break; - case nameof(GetLampUnit.IsEnabled): - desc.summary = "Whether the intensity is larger than 0."; + var getLampUnit = port.unit as GetLampUnit; + switch (getLampUnit!.DataType) { + case LampDataType.OnOff: + desc.label = "Lit"; + desc.summary = "On or off."; + break; + case LampDataType.Status: + desc.label = "Status"; + desc.summary = "On, off or blinking."; + break; + case LampDataType.Intensity: + desc.label = "Intensity"; + desc.summary = "The intensity of the lamp (value depends on the maximal intensity of the mapping)."; + break; + case LampDataType.Color: + desc.label = "Color"; + desc.summary = "The color of the lamp."; + break; + default: + throw new ArgumentOutOfRangeException(); + } break; } } diff --git a/Editor/Descriptors/GetPlayerIdUnitDescriptor.cs b/Editor/Descriptors/GetPlayerIdUnitDescriptor.cs new file mode 100644 index 0000000..78be8b1 --- /dev/null +++ b/Editor/Descriptors/GetPlayerIdUnitDescriptor.cs @@ -0,0 +1,50 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; +using VisualPinball.Unity.Editor; +using IconSize = VisualPinball.Unity.Editor.IconSize; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Descriptor(typeof(GetPlayerIdUnit))] + public class GetPlayerIdUnitDescriptor : UnitDescriptor + { + public GetPlayerIdUnitDescriptor(GetPlayerIdUnit target) : base(target) + { + } + + protected override string DefinedSummary() + { + return "This node returns either the first, the last, or the current player ID."; + } + + protected override EditorTexture DefinedIcon() => EditorTexture.Single(Unity.Editor.Icons.PlayerVariable); + + protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) + { + base.DefinedPort(port, desc); + + switch (port.key) { + case nameof(GetPlayerIdUnit.PlayerId): + desc.summary = "The player ID as configured in the node header."; + break; + } + } + } +} diff --git a/Editor/Descriptors/GetPlayerIdUnitDescriptor.cs.meta b/Editor/Descriptors/GetPlayerIdUnitDescriptor.cs.meta new file mode 100644 index 0000000..cb49c1a --- /dev/null +++ b/Editor/Descriptors/GetPlayerIdUnitDescriptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7cf09367a2092594fb8a9aef111becd2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Descriptors/GetSwitchUnitDescriptor.cs b/Editor/Descriptors/GetSwitchUnitDescriptor.cs new file mode 100644 index 0000000..862b1f1 --- /dev/null +++ b/Editor/Descriptors/GetSwitchUnitDescriptor.cs @@ -0,0 +1,53 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; +using VisualPinball.Unity.Editor; +using IconSize = VisualPinball.Unity.Editor.IconSize; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Descriptor(typeof(GetSwitchUnit))] + public class GetSwitchUnitDescriptor : UnitDescriptor + { + public GetSwitchUnitDescriptor(GetSwitchUnit target) : base(target) + { + } + + protected override string DefinedSummary() + { + return "This node retrieves the current status of the switch."; + } + + protected override EditorTexture DefinedIcon() => EditorTexture.Single(Unity.Editor.Icons.Switch(false, IconSize.Large, IconColor.Orange)); + + protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) + { + base.DefinedPort(port, desc); + + switch (port.key) { + case nameof(GetSwitchUnit.Id): + desc.summary = "Switch ID to check if enabled."; + break; + case nameof(GetSwitchUnit.IsEnabled): + desc.summary = "Whether the switch is enabled."; + break; + } + } + } +} diff --git a/Editor/Descriptors/GetSwitchUnitDescriptor.cs.meta b/Editor/Descriptors/GetSwitchUnitDescriptor.cs.meta new file mode 100644 index 0000000..bf2658d --- /dev/null +++ b/Editor/Descriptors/GetSwitchUnitDescriptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f4ba0e998e0174672a7439dd7e7d4398 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Descriptors/GetVariableUnitDescriptor.cs b/Editor/Descriptors/GetVariableUnitDescriptor.cs new file mode 100644 index 0000000..d5584ac --- /dev/null +++ b/Editor/Descriptors/GetVariableUnitDescriptor.cs @@ -0,0 +1,74 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Descriptor(typeof(GetPlayerVariableUnit))] + public class GetPlayerVariableUnitDescriptor : UnitDescriptor + { + public GetPlayerVariableUnitDescriptor(GetPlayerVariableUnit target) : base(target) + { + } + + protected override string DefinedSummary() + { + return "This node retrieves the value of a given player variable."; + } + + protected override EditorTexture DefinedIcon() => EditorTexture.Single(Unity.Editor.Icons.PlayerVariable); + + protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) + { + base.DefinedPort(port, desc); + + switch (port.key) { + case nameof(GetPlayerVariableUnit.Value): + desc.summary = "The current value of the player variable."; + break; + } + } + } + + [Descriptor(typeof(GetTableVariableUnit))] + public class GetTableVariableUnitDescriptor : UnitDescriptor + { + public GetTableVariableUnitDescriptor(GetTableVariableUnit target) : base(target) + { + } + + protected override string DefinedSummary() + { + return "This node retrieves the value of a given table variable."; + } + + protected override EditorTexture DefinedIcon() => EditorTexture.Single(Unity.Editor.Icons.TableVariable); + + protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) + { + base.DefinedPort(port, desc); + + switch (port.key) { + case nameof(GetTableVariableUnit.Value): + desc.summary = "The current value of the table variable."; + break; + } + } + } +} diff --git a/Editor/Descriptors/GetVariableUnitDescriptor.cs.meta b/Editor/Descriptors/GetVariableUnitDescriptor.cs.meta new file mode 100644 index 0000000..643c6c6 --- /dev/null +++ b/Editor/Descriptors/GetVariableUnitDescriptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5692d07afb030ce4cae7363be616d4ff +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Descriptors/IncreaseVariableUnitDescriptor.cs b/Editor/Descriptors/IncreaseVariableUnitDescriptor.cs new file mode 100644 index 0000000..816de6a --- /dev/null +++ b/Editor/Descriptors/IncreaseVariableUnitDescriptor.cs @@ -0,0 +1,80 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Descriptor(typeof(IncreasePlayerVariableUnit))] + public class IncreasePlayerVariableUnitDescriptor : UnitDescriptor + { + public IncreasePlayerVariableUnitDescriptor(IncreasePlayerVariableUnit target) : base(target) + { + } + + protected override string DefinedSummary() + { + return "This node increases the value of a given player variable.\n\nTo decrease, use a negative value."; + } + + protected override EditorTexture DefinedIcon() => EditorTexture.Single(Unity.Editor.Icons.PlayerVariable); + + protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) + { + base.DefinedPort(port, desc); + + switch (port.key) { + case nameof(IncreasePlayerVariableUnit.Value): + desc.summary = "The value to add to the existing value."; + break; + case nameof(IncreasePlayerVariableUnit.OutputValue): + desc.summary = "The final increased value."; + break; + } + } + } + + [Descriptor(typeof(IncreaseTableVariableUnit))] + public class IncreaseTableVariableUnitDescriptor : UnitDescriptor + { + public IncreaseTableVariableUnitDescriptor(IncreaseTableVariableUnit target) : base(target) + { + } + + protected override string DefinedSummary() + { + return "This node increases the value of a given table variable.\n\nTo decrease, use a negative value."; + } + + protected override EditorTexture DefinedIcon() => EditorTexture.Single(Unity.Editor.Icons.TableVariable); + + protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) + { + base.DefinedPort(port, desc); + + switch (port.key) { + case nameof(IncreaseTableVariableUnit.Value): + desc.summary = "The value to add to the existing value."; + break; + case nameof(IncreasePlayerVariableUnit.OutputValue): + desc.summary = "The final increased value."; + break; + } + } + } +} diff --git a/Editor/Descriptors/IncreaseVariableUnitDescriptor.cs.meta b/Editor/Descriptors/IncreaseVariableUnitDescriptor.cs.meta new file mode 100644 index 0000000..9bb7cb1 --- /dev/null +++ b/Editor/Descriptors/IncreaseVariableUnitDescriptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2d7e9d26e5a2b9245874e431b7a419ce +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Descriptors/LampEventUnitDescriptor.cs b/Editor/Descriptors/LampEventUnitDescriptor.cs index ee9bb61..e6107f9 100644 --- a/Editor/Descriptors/LampEventUnitDescriptor.cs +++ b/Editor/Descriptors/LampEventUnitDescriptor.cs @@ -38,16 +38,17 @@ protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) { base.DefinedPort(port, desc); - switch (port.key) { - case nameof(LampEventUnit.Id): - desc.summary = "The ID of the lamp that changed its intensity."; - break; - case nameof(LampEventUnit.Value): - desc.summary = "The new intensity of the lamp (0-1)."; - break; - case nameof(LampEventUnit.IsEnabled): - desc.summary = "Whether the intensity is larger than 0."; - break; + if (port.key == nameof(LampEventUnit.IsEnabled)) { + desc.summary = "Whether the intensity is larger than 0."; + } + else if (port.key == nameof(LampEventUnit.Value)) { + desc.summary = "The new intensity of the lamp (0-1)."; + } + else if (int.TryParse(port.key, out int id)) { + id += 1; + + desc.label = $"Lamp ID {id}"; + desc.summary = $"Lamp ID {id} to look for a change in intensity."; } } } diff --git a/Editor/Descriptors/LampSequenceUnitDescriptor.cs b/Editor/Descriptors/LampSequenceUnitDescriptor.cs new file mode 100644 index 0000000..a51d8f4 --- /dev/null +++ b/Editor/Descriptors/LampSequenceUnitDescriptor.cs @@ -0,0 +1,55 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Descriptor(typeof(LampSequenceUnit))] + public class LampSequenceUnitDescriptor : UnitDescriptor + { + public LampSequenceUnitDescriptor(LampSequenceUnit target) : base(target) + { + } + + protected override string DefinedSummary() + { + return "This node turns on/off lamps in a sequence defined by lamp ids."; + } + + protected override EditorTexture DefinedIcon() => EditorTexture.Single(Unity.Editor.Icons.LampSequence); + + protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) + { + base.DefinedPort(port, desc); + + if (port.key == nameof(LampSequenceUnit.Step)) { + desc.summary = "How position is increased and to how many lights the intensity is applied to."; + } + else if (port.key == nameof(LampSequenceUnit.Value)) { + desc.summary = "The intensity to apply to the current step (0-1)."; + } + else if (int.TryParse(port.key, out int id)) { + id += 1; + + desc.label = $"Lamp ID {id}"; + desc.summary = $"Lamp ID {id} to cycle through."; + } + } + } +} diff --git a/Editor/Descriptors/LampSequenceUnitDescriptor.cs.meta b/Editor/Descriptors/LampSequenceUnitDescriptor.cs.meta new file mode 100644 index 0000000..bdcdba4 --- /dev/null +++ b/Editor/Descriptors/LampSequenceUnitDescriptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 238a5a8d7a46e47808155b5d126bab7c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Descriptors/MultiUnitDescriptor.cs b/Editor/Descriptors/MultiUnitDescriptor.cs new file mode 100644 index 0000000..bc987bc --- /dev/null +++ b/Editor/Descriptors/MultiUnitDescriptor.cs @@ -0,0 +1,44 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + public abstract class MultiUnitDescriptor : UnitDescriptor where TUnit : class, IUnit + { + protected abstract string ItemLabel(int id); + protected abstract string ItemDescription(int id); + + protected MultiUnitDescriptor(TUnit target) : base(target) + { + } + + protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) + { + base.DefinedPort(port, desc); + + if (int.TryParse(port.key, out int id)) { + id += 1; + + desc.label = ItemLabel(id); + desc.summary = ItemDescription(id); + } + } + } +} diff --git a/Editor/Descriptors/MultiUnitDescriptor.cs.meta b/Editor/Descriptors/MultiUnitDescriptor.cs.meta new file mode 100644 index 0000000..ea51305 --- /dev/null +++ b/Editor/Descriptors/MultiUnitDescriptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9e20ce6742d43d040b9cb4d05b343275 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Descriptors/PulseCoilUnitDescriptor.cs b/Editor/Descriptors/PulseCoilUnitDescriptor.cs index 522dcea..201f107 100644 --- a/Editor/Descriptors/PulseCoilUnitDescriptor.cs +++ b/Editor/Descriptors/PulseCoilUnitDescriptor.cs @@ -43,13 +43,14 @@ protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) { base.DefinedPort(port, desc); - switch (port.key) { - case nameof(PulseCoilUnit.Id): - desc.summary = "The ID of the coil to be pulsed."; - break; - case nameof(PulseCoilUnit.PulseDuration): - desc.summary = "The time in milliseconds until the coil is disabled again."; - break; + if (port.key == nameof(PulseCoilUnit.PulseDuration)) { + desc.summary = "The time in milliseconds until the coils are disabled again."; + } + else if (int.TryParse(port.key, out int id)) { + id += 1; + + desc.label = $"Coil ID {id}"; + desc.summary = $"Coil ID {id} of the coil to be pulsed."; } } } diff --git a/Editor/Descriptors/PulseSwitchUnitDescriptor.cs b/Editor/Descriptors/PulseSwitchUnitDescriptor.cs new file mode 100644 index 0000000..37f1209 --- /dev/null +++ b/Editor/Descriptors/PulseSwitchUnitDescriptor.cs @@ -0,0 +1,57 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; +using VisualPinball.Unity.Editor; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Descriptor(typeof(PulseSwitchUnit))] + public class PulseSwitchUnitDescriptor : UnitDescriptor + { + public PulseSwitchUnitDescriptor(PulseSwitchUnit target) : base(target) + { + } + + protected override string DefinedSummary() + { + return "This node enables switches defined by their IDs and disables it after a given delay."; + } + + protected override EditorTexture DefinedIcon() + { + var texture = VisualPinball.Unity.Editor.Icons.Switch(false, VisualPinball.Unity.Editor.IconSize.Large, IconColor.Orange); + return EditorTexture.Single(texture); + } + + protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) + { + base.DefinedPort(port, desc); + + if (port.key == nameof(PulseSwitchUnit.PulseDelay)) { + desc.summary = "The time in milliseconds until the switches are disabled again."; + } + else if (int.TryParse(port.key, out int id)) { + id += 1; + + desc.label = $"Switch ID {id}"; + desc.summary = $"Switch ID {id} of the switch to be pulsed."; + } + } + } +} diff --git a/Editor/Descriptors/PulseSwitchUnitDescriptor.cs.meta b/Editor/Descriptors/PulseSwitchUnitDescriptor.cs.meta new file mode 100644 index 0000000..26e4e9e --- /dev/null +++ b/Editor/Descriptors/PulseSwitchUnitDescriptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0e534243fbcfb4866bbd39ff3e0b2032 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Descriptors/SetCoilUnitDescriptor.cs b/Editor/Descriptors/SetCoilUnitDescriptor.cs index 8d628cc..41e3cb0 100644 --- a/Editor/Descriptors/SetCoilUnitDescriptor.cs +++ b/Editor/Descriptors/SetCoilUnitDescriptor.cs @@ -30,7 +30,7 @@ public SetCoilUnitDescriptor(SetCoilUnit target) : base(target) protected override string DefinedSummary() { - return "This node assigns a given value to a coil defined by its ID."; + return "This node assigns a given value to coils defined by their IDs."; } protected override EditorTexture DefinedIcon() @@ -43,13 +43,14 @@ protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) { base.DefinedPort(port, desc); - switch (port.key) { - case nameof(SetCoilUnit.Id): - desc.summary = "The ID of the coil to be set."; - break; - case nameof(SetCoilUnit.IsEnabled): - desc.summary = "The value to assign to the coil."; - break; + if (port.key == nameof(SetCoilUnit.IsEnabled)) { + desc.summary = "The value to assign to the coils."; + } + else if (int.TryParse(port.key, out int id)) { + id += 1; + + desc.label = $"Coil ID {id}"; + desc.summary = $"Coil ID {id} of the coil to be set."; } } } diff --git a/Editor/Descriptors/SetLampUnitDescriptor.cs b/Editor/Descriptors/SetLampUnitDescriptor.cs index bcfc324..b9bedf4 100644 --- a/Editor/Descriptors/SetLampUnitDescriptor.cs +++ b/Editor/Descriptors/SetLampUnitDescriptor.cs @@ -16,6 +16,7 @@ // ReSharper disable UnusedType.Global +using System; using Unity.VisualScripting; using VisualPinball.Unity.Editor; using IconSize = VisualPinball.Unity.Editor.IconSize; @@ -40,13 +41,35 @@ protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) { base.DefinedPort(port, desc); - switch (port.key) { - case nameof(SetLampUnit.Id): - desc.summary = "The ID of the lamp for which the intensity is returned."; - break; - case nameof(SetLampUnit.Value): - desc.summary = "The intensity of the lamp (0-1)."; - break; + if (port.key == nameof(SetLampUnit.Value)) { + var setLampUnit = port.unit as SetLampUnit; + switch (setLampUnit!.DataType) { + case LampDataType.OnOff: + desc.label = "Lit?"; + desc.summary = "On or off."; + break; + case LampDataType.Status: + desc.label = "Status"; + desc.summary = "On, off or blinking."; + break; + case LampDataType.Intensity: + desc.label = "Intensity"; + desc.summary = "The intensity of the lamp (0-1)."; + break; + case LampDataType.Color: + desc.label = "Color"; + desc.summary = "The color of the lamp."; + break; + + default: + throw new ArgumentOutOfRangeException(); + } + } + else if (int.TryParse(port.key, out int id)) { + id += 1; + + desc.label = $"Lamp ID {id}"; + desc.summary = $"Lamp ID {id} of the lamp to set the intensity"; } } } diff --git a/Editor/Descriptors/SetSwitchUnitDescriptor.cs b/Editor/Descriptors/SetSwitchUnitDescriptor.cs new file mode 100644 index 0000000..4ff6c99 --- /dev/null +++ b/Editor/Descriptors/SetSwitchUnitDescriptor.cs @@ -0,0 +1,57 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; +using VisualPinball.Unity.Editor; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Descriptor(typeof(SetSwitchUnit))] + public class SetSwitchUnitDescriptor : UnitDescriptor + { + public SetSwitchUnitDescriptor(SetSwitchUnit target) : base(target) + { + } + + protected override string DefinedSummary() + { + return "This node assigns a given value to switches defined by their IDs."; + } + + protected override EditorTexture DefinedIcon() + { + var texture = VisualPinball.Unity.Editor.Icons.Switch(false, VisualPinball.Unity.Editor.IconSize.Large, IconColor.Orange); + return EditorTexture.Single(texture); + } + + protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) + { + base.DefinedPort(port, desc); + + if (port.key == nameof(SetSwitchUnit.IsEnabled)) { + desc.summary = "The value to assign to the switches."; + } + else if (int.TryParse(port.key, out int id)) { + id += 1; + + desc.label = $"Switch ID {id}"; + desc.summary = $"Switch ID {id} of the switch to be set."; + } + } + } +} diff --git a/Editor/Descriptors/SetSwitchUnitDescriptor.cs.meta b/Editor/Descriptors/SetSwitchUnitDescriptor.cs.meta new file mode 100644 index 0000000..a6077f4 --- /dev/null +++ b/Editor/Descriptors/SetSwitchUnitDescriptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2a039bc39631d43e88527e8b99393b43 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Descriptors/SetVariableUnitDescriptor.cs b/Editor/Descriptors/SetVariableUnitDescriptor.cs new file mode 100644 index 0000000..6e8c4d1 --- /dev/null +++ b/Editor/Descriptors/SetVariableUnitDescriptor.cs @@ -0,0 +1,81 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Descriptor(typeof(SetPlayerVariableUnit))] + public class SetPlayerVariableUnitDescriptor : UnitDescriptor + { + public SetPlayerVariableUnitDescriptor(SetPlayerVariableUnit target) : base(target) + { + } + + protected override string DefinedSummary() + { + return "This node sets the value of a given player variable."; + } + + protected override EditorTexture DefinedIcon() => EditorTexture.Single(Unity.Editor.Icons.PlayerVariable); + + protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) + { + base.DefinedPort(port, desc); + + switch (port.key) { + case nameof(SetPlayerVariableUnit.Value): + desc.summary = "The new value of the player variable."; + break; + case nameof(SetPlayerVariableUnit.OutputValue): + desc.summary = "The new value of the player variable."; + break; + } + } + } + + [Descriptor(typeof(SetTableVariableUnit))] + public class SetTableVariableUnitDescriptor : UnitDescriptor + { + public SetTableVariableUnitDescriptor(SetTableVariableUnit target) : base(target) + { + } + + protected override string DefinedSummary() + { + return "This node sets the value of a given table variable."; + } + + protected override EditorTexture DefinedIcon() => EditorTexture.Single(Unity.Editor.Icons.TableVariable); + + protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) + { + base.DefinedPort(port, desc); + + switch (port.key) { + case nameof(SetTableVariableUnit.Value): + desc.summary = "The new value of the table variable."; + break; + + case nameof(SetTableVariableUnit.OutputValue): + desc.summary = "The new value of the table variable."; + break; + } + } + } +} diff --git a/Editor/Descriptors/SetVariableUnitDescriptor.cs.meta b/Editor/Descriptors/SetVariableUnitDescriptor.cs.meta new file mode 100644 index 0000000..769832b --- /dev/null +++ b/Editor/Descriptors/SetVariableUnitDescriptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0c6e91a4afe68844ebd38d53896e3ca4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Descriptors/SwitchEnabledEventUnitDescriptor.cs b/Editor/Descriptors/SwitchEnabledEventUnitDescriptor.cs new file mode 100644 index 0000000..1e20d18 --- /dev/null +++ b/Editor/Descriptors/SwitchEnabledEventUnitDescriptor.cs @@ -0,0 +1,49 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Descriptor(typeof(SwitchEnabledEventUnit))] + public class SwitchEnabledEventUnitDescriptor : UnitDescriptor + { + public SwitchEnabledEventUnitDescriptor(SwitchEnabledEventUnit target) : base(target) + { + } + + protected override string DefinedSummary() + { + return "This node triggers an event when a switch in the list of given ID is enabled."; + } + + protected override EditorTexture DefinedIcon() => EditorTexture.Single(Unity.Editor.Icons.SwitchEvent); + + protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) + { + base.DefinedPort(port, desc); + + if (int.TryParse(port.key, out int id)) { + id += 1; + + desc.label = $"Switch ID {id}"; + desc.summary = $"Switch ID {id} to look for enabled status."; + } + } + } +} diff --git a/Editor/Descriptors/SwitchEnabledEventUnitDescriptor.cs.meta b/Editor/Descriptors/SwitchEnabledEventUnitDescriptor.cs.meta new file mode 100644 index 0000000..7998fd4 --- /dev/null +++ b/Editor/Descriptors/SwitchEnabledEventUnitDescriptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 32e28bb31bbaf4ddeac7824d4428df1f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Descriptors/SwitchEventUnitDescriptor.cs b/Editor/Descriptors/SwitchEventUnitDescriptor.cs index c655393..cb16d76 100644 --- a/Editor/Descriptors/SwitchEventUnitDescriptor.cs +++ b/Editor/Descriptors/SwitchEventUnitDescriptor.cs @@ -38,13 +38,14 @@ protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) { base.DefinedPort(port, desc); - switch (port.key) { - case nameof(SwitchEventUnit.Id): - desc.summary = "The ID of the switch that changed its value."; - break; - case nameof(SwitchEventUnit.IsEnabled): - desc.summary = "The new value of the switch, true if enabled, false otherwise."; - break; + if (port.key == nameof(SwitchEventUnit.IsEnabled)) { + desc.summary = "The new value of the switch, true if enabled, false otherwise."; + } + else if (int.TryParse(port.key, out int id)) { + id += 1; + + desc.label = $"Switch ID {id}"; + desc.summary = $"Switch ID {id} to look for a change status."; } } } diff --git a/Editor/Descriptors/SetLightUnitDescriptor.cs b/Editor/Descriptors/SwitchLampUnitDescriptor.cs similarity index 57% rename from Editor/Descriptors/SetLightUnitDescriptor.cs rename to Editor/Descriptors/SwitchLampUnitDescriptor.cs index f50d9d5..37c4f23 100644 --- a/Editor/Descriptors/SetLightUnitDescriptor.cs +++ b/Editor/Descriptors/SwitchLampUnitDescriptor.cs @@ -22,16 +22,16 @@ namespace VisualPinball.Unity.VisualScripting.Editor { - [Descriptor(typeof(SetLightUnit))] - public class SetLightUnitDescriptor : UnitDescriptor + [Descriptor(typeof(SwitchLampUnit))] + public class SwitchLampUnitDescriptor : UnitDescriptor { - public SetLightUnitDescriptor(SetLightUnit target) : base(target) + public SwitchLampUnitDescriptor(SwitchLampUnit target) : base(target) { } protected override string DefinedSummary() { - return "This node assigns a given value to a light or light group in the scene. \n\nNote that this doesn't pass through the gamelogic engine, thus no event will be triggered. However, it allows you to drive non-mapped lights as well."; + return "This node enabled or disables lamps based on matching a source value with a specifed value."; } protected override EditorTexture DefinedIcon() => EditorTexture.Single(Unity.Editor.Icons.Light(IconSize.Large, IconColor.Orange)); @@ -40,18 +40,14 @@ protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) { base.DefinedPort(port, desc); - switch (port.key) { - case nameof(SetLightUnit.LampComponent): - desc.summary = "The light component whose value you want to change. Assigning a light group will change all lights in the group."; - break; - - case nameof(SetLightUnit.Value): - desc.summary = "The intensity to apply (0-1)."; - break; + if (port.key == nameof(SwitchLampUnit.SourceValue)) { + desc.summary = "Source value to use for matching"; + } + else if (int.TryParse(port.key, out int id)) { + id += 1; - case nameof(SetLightUnit.ColorChannel): - desc.summary = "Which color channel to use. For non-RGB lights, use alpha."; - break; + desc.label = $"Lamp ID {id}"; + desc.summary = $"Lamp ID {id} to enable if specified Value matches source Value, or disable if specified Value does not match source Value"; } } } diff --git a/Editor/Descriptors/SwitchLampUnitDescriptor.cs.meta b/Editor/Descriptors/SwitchLampUnitDescriptor.cs.meta new file mode 100644 index 0000000..37dc01b --- /dev/null +++ b/Editor/Descriptors/SwitchLampUnitDescriptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 93c352919cdce4676b64df9c635d6ad7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Descriptors/SetLightSequenceUnitDescriptor.cs b/Editor/Descriptors/UpdateDisplayUnitDescriptor.cs similarity index 51% rename from Editor/Descriptors/SetLightSequenceUnitDescriptor.cs rename to Editor/Descriptors/UpdateDisplayUnitDescriptor.cs index b31266c..34bf0da 100644 --- a/Editor/Descriptors/SetLightSequenceUnitDescriptor.cs +++ b/Editor/Descriptors/UpdateDisplayUnitDescriptor.cs @@ -1,62 +1,56 @@ -// Visual Pinball Engine -// Copyright (C) 2022 freezy and VPE Team -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -// ReSharper disable UnusedType.Global - -using Unity.VisualScripting; -using VisualPinball.Unity.Editor; -using IconSize = VisualPinball.Unity.Editor.IconSize; - -namespace VisualPinball.Unity.VisualScripting.Editor -{ - [Descriptor(typeof(SetLightSequenceUnit))] - public class SetLightSequenceUnitDescriptor : UnitDescriptor - { - public SetLightSequenceUnitDescriptor(SetLightSequenceUnit target) : base(target) - { - } - - protected override string DefinedSummary() - { - return "This node sets the intensity of the lights at the next position within a light group. On each execution, the position increases by the number of steps. The number of lights set is the step number.\n\nExample: Four lights, A B C D, step size = 2. First run, lights A and B are set. Second run, lights C and D are set."; - } - - protected override EditorTexture DefinedIcon() => EditorTexture.Single(Unity.Editor.Icons.LampSequence); - - protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) - { - base.DefinedPort(port, desc); - - switch (port.key) { - case nameof(SetLightSequenceUnit.LightGroup): - desc.summary = "The light group to cycle through."; - break; - - case nameof(SetLightSequenceUnit.Value): - desc.summary = "The intensity to apply to the current step (0-1)."; - break; - - case nameof(SetLightSequenceUnit.ColorChannel): - desc.summary = "Which color channel to use. For non-RGB lights, use alpha."; - break; - - case nameof(SetLightSequenceUnit.Step): - desc.summary = "How position is increased and to how many lights the intensity is applied to."; - break; - } - } - } -} +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; +using VisualPinball.Unity.Editor; +using IconSize = VisualPinball.Unity.Editor.IconSize; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Descriptor(typeof(UpdateDisplayUnit))] + public class UpdateDisplayUnitDescriptor : UnitDescriptor + { + public UpdateDisplayUnitDescriptor(UpdateDisplayUnit target) : base(target) + { + } + + protected override string DefinedSummary() + { + return "This node takes in a value and sends it to the display connected through the given ID.\n\nDisplay might be able display different types of data, so depending on how you configure your display in the Visual Scripting Gamelogic Engine, you might get multiple data inputs."; + } + + protected override EditorTexture DefinedIcon() => EditorTexture.Single(Unity.Editor.Icons.UpdateDisplay); + + protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) + { + base.DefinedPort(port, desc); + + switch (port.key) { + case nameof(UpdateDisplayUnit.NumericInput): + desc.summary = "Sets the display to a new numerical value."; + break; + case nameof(UpdateDisplayUnit.TextInput): + desc.summary = "Sets the display to a new text value."; + break; + case nameof(UpdateDisplayUnit.SegmentInput): + desc.summary = "Updates the display with new frame data."; + break; + } + } + } +} diff --git a/Editor/Descriptors/UpdateDisplayUnitDescriptor.cs.meta b/Editor/Descriptors/UpdateDisplayUnitDescriptor.cs.meta new file mode 100644 index 0000000..2406c9a --- /dev/null +++ b/Editor/Descriptors/UpdateDisplayUnitDescriptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9880082450879fd4788ce30e6c79ede0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Descriptors/VariableChangedEventUnitDescriptor.cs b/Editor/Descriptors/VariableChangedEventUnitDescriptor.cs new file mode 100644 index 0000000..4d91de4 --- /dev/null +++ b/Editor/Descriptors/VariableChangedEventUnitDescriptor.cs @@ -0,0 +1,81 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Descriptor(typeof(PlayerVariableChangedEventUnit))] + public class PlayerVariableChangedEventUnitDescriptor : UnitDescriptor + { + public PlayerVariableChangedEventUnitDescriptor(PlayerVariableChangedEventUnit target) : base(target) + { + } + + protected override string DefinedSummary() + { + return "This event is emitted when a given player variable changes."; + } + + protected override EditorTexture DefinedIcon() => EditorTexture.Single(Unity.Editor.Icons.PlayerVariableEvent); + + protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) + { + base.DefinedPort(port, desc); + + switch (port.key) { + case nameof(PlayerVariableChangedEventUnit.OldValue): + desc.summary = "The previous value of the player variable."; + break; + case nameof(PlayerVariableChangedEventUnit.NewValue): + desc.summary = "The new value of the player variable."; + break; + } + } + } + + + [Descriptor(typeof(TableVariableChangedEventUnit))] + public class TableVariableChangedEventUnitDescriptor : UnitDescriptor + { + public TableVariableChangedEventUnitDescriptor(TableVariableChangedEventUnit target) : base(target) + { + } + + protected override string DefinedSummary() + { + return "This event is emitted when a given table variable changes."; + } + + protected override EditorTexture DefinedIcon() => EditorTexture.Single(Unity.Editor.Icons.TableVariableEvent); + + protected override void DefinedPort(IUnitPort port, UnitPortDescription desc) + { + base.DefinedPort(port, desc); + + switch (port.key) { + case nameof(TableVariableChangedEventUnit.OldValue): + desc.summary = "The previous value of the table variable."; + break; + case nameof(TableVariableChangedEventUnit.NewValue): + desc.summary = "The new value of the table variable."; + break; + } + } + } +} diff --git a/Editor/Descriptors/VariableChangedEventUnitDescriptor.cs.meta b/Editor/Descriptors/VariableChangedEventUnitDescriptor.cs.meta new file mode 100644 index 0000000..9a99081 --- /dev/null +++ b/Editor/Descriptors/VariableChangedEventUnitDescriptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9eadacb1f3a28324cbbf12296ca1f057 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Inspectors/DisplayDefinitionInspector.cs b/Editor/Inspectors/DisplayDefinitionInspector.cs new file mode 100644 index 0000000..a88e57c --- /dev/null +++ b/Editor/Inspectors/DisplayDefinitionInspector.cs @@ -0,0 +1,76 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.Collections.Generic; +using System.Linq; +using Unity.VisualScripting; +using UnityEditor; +using UnityEngine; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Inspector(typeof(DisplayDefinition))] + public class DisplayDefinitionInspector : GleInspector + { + public DisplayDefinitionInspector(Metadata metadata) : base(metadata) { } + + protected override void OnGUI(Rect position, GUIContent label) + { + // can't get this from the flow + var gle = Gle; + if (gle != null) { + if (gle.Displays == null || gle.Displays.Count(p => !string.IsNullOrEmpty(p.Id)) == 0) { + ErrorMessage = "No displays defined."; + + } else { + var varNames = new List { "None" } + .Concat(gle.Displays.Select(d => d.Id)) + .ToArray(); + var currentDisplayDef = metadata.value as DisplayDefinition; + var currentIndex = 0; + if (currentDisplayDef != null) { + var displayDef = gle.Displays.FirstOrDefault(p => p.Id == currentDisplayDef!.Id); + currentIndex = displayDef != null ? Array.IndexOf(gle.Displays, displayDef) + 1 : 0; + } + + var newIndex = EditorGUI.Popup(position, currentIndex, varNames); + metadata.RecordUndo(); + metadata.value = newIndex == 0 ? null : gle.Displays[newIndex - 1]; + ErrorMessage = null; + } + } + + if (ErrorMessage != null) { + position.height -= EditorGUIUtility.standardVerticalSpacing; + EditorGUI.HelpBox(position, ErrorMessage, MessageType.Error); + } + } + + public override float GetAdaptiveWidth() => LudiqGUIUtility.currentInspectorWidth; + + protected override float GetHeight(float width, GUIContent label) + { + if (ErrorMessage != null) { + var height = LudiqGUIUtility.GetHelpBoxHeight(ErrorMessage, MessageType.Error, width); + height += EditorGUIUtility.standardVerticalSpacing; + return height; + } + + return EditorGUIUtility.singleLineHeight; + } + } +} diff --git a/Editor/Inspectors/DisplayDefinitionInspector.cs.meta b/Editor/Inspectors/DisplayDefinitionInspector.cs.meta new file mode 100644 index 0000000..67d58be --- /dev/null +++ b/Editor/Inspectors/DisplayDefinitionInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1ad1b15551c31b94e97bb65c02b01551 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Inspectors/EventDefinitionInspector.cs b/Editor/Inspectors/EventDefinitionInspector.cs new file mode 100644 index 0000000..e8a359c --- /dev/null +++ b/Editor/Inspectors/EventDefinitionInspector.cs @@ -0,0 +1,76 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System.Collections.Generic; +using System.Linq; +using Unity.VisualScripting; +using UnityEditor; +using UnityEngine; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Inspector(typeof(EventDefinition))] + public class EventDefinitionInspector : GleInspector + { + public EventDefinitionInspector(Metadata metadata) : base(metadata) { } + + protected override void OnGUI(Rect position, GUIContent label) + { + // can't get this from the flow + var gle = Gle; + if (gle != null) { + var eventDefinitions = gle.EventDefinitions; + if (eventDefinitions == null || eventDefinitions.Count(p => !string.IsNullOrEmpty(p.Name)) == 0) { + ErrorMessage = "No events defined."; + + } else { + var eventNames = new List { "None" } + .Concat(eventDefinitions.Select(d => d.Name)) + .ToArray(); + var currentEventDef = metadata.value as EventDefinition; + var currentIndex = 0; + if (currentEventDef != null) { + var eventDef = eventDefinitions.FirstOrDefault(p => p.Id == currentEventDef!.Id); + currentIndex = eventDef != null ? eventDefinitions.IndexOf(eventDef) + 1 : 0; + } + + var newIndex = EditorGUI.Popup(position, currentIndex, eventNames); + metadata.RecordUndo(); + metadata.value = newIndex == 0 ? null : eventDefinitions[newIndex - 1]; + ErrorMessage = null; + } + } + + if (ErrorMessage != null) { + position.height -= EditorGUIUtility.standardVerticalSpacing; + EditorGUI.HelpBox(position, ErrorMessage, MessageType.Error); + } + } + + public override float GetAdaptiveWidth() => LudiqGUIUtility.currentInspectorWidth; + + protected override float GetHeight(float width, GUIContent label) + { + if (ErrorMessage != null) { + var height = LudiqGUIUtility.GetHelpBoxHeight(ErrorMessage, MessageType.Error, width); + height += EditorGUIUtility.standardVerticalSpacing; + return height; + } + + return EditorGUIUtility.singleLineHeight; + } + } +} diff --git a/Editor/Inspectors/EventDefinitionInspector.cs.meta b/Editor/Inspectors/EventDefinitionInspector.cs.meta new file mode 100644 index 0000000..d5c8960 --- /dev/null +++ b/Editor/Inspectors/EventDefinitionInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d3072639de8185c4eb378273be9ce25a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Inspectors/GleInspector.cs b/Editor/Inspectors/GleInspector.cs new file mode 100644 index 0000000..b3145f6 --- /dev/null +++ b/Editor/Inspectors/GleInspector.cs @@ -0,0 +1,51 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using Unity.VisualScripting; +using VisualPinball.Unity; +using VisualPinball.Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + public abstract class GleInspector : Inspector + { + protected GleInspector(Metadata metadata) : base(metadata) { } + + private const string NoGleError = "Unable to find Gamelogic Engine in scene."; + + protected VisualScriptingGamelogicEngine Gle { + get { + if (_gle != null) { + return _gle; + } + var tableComponent = TableSelector.Instance.SelectedOrFirstTable; + if (tableComponent != null) { + _gle = tableComponent.GetComponentInChildren(); + } + if (_gle == null && ErrorMessage == null) { + ErrorMessage = NoGleError; + + } else if (_gle != null && ErrorMessage == NoGleError) { + ErrorMessage = null; + } + return _gle; + } + } + protected string ErrorMessage; + + private VisualScriptingGamelogicEngine _gle; + } +} diff --git a/Editor/Inspectors/GleInspector.cs.meta b/Editor/Inspectors/GleInspector.cs.meta new file mode 100644 index 0000000..7dac231 --- /dev/null +++ b/Editor/Inspectors/GleInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fcd362b6a8f17ea438744161a4e990ed +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Inspectors/LampIdValueInspector.cs b/Editor/Inspectors/LampIdValueInspector.cs new file mode 100644 index 0000000..b53b437 --- /dev/null +++ b/Editor/Inspectors/LampIdValueInspector.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + + public sealed class LampIdValueInspector : Inspector + { + private static readonly int LabelPadding = 5; + + public LampIdValueInspector(Metadata metadata, Func> getSuggestions) : base(metadata) + { + Ensure.That(nameof(getSuggestions)).IsNotNull(getSuggestions); + + this.getSuggestions = getSuggestions; + } + + public Func> getSuggestions { get; } + + + protected override float GetHeight(float width, GUIContent label) + { + return HeightWithLabel(metadata, width, GetFieldHeight(width, label), label); + } + + private float GetFieldHeight(float width, GUIContent label) + { + return EditorGUIUtility.singleLineHeight; + } + + private List suggestions = new List(); + + protected override void OnGUI(Rect position, GUIContent label) + { + LampIdValue lampIdValue = LampIdValue.FromJson((string)metadata.value); + + var valueLabelWidth = EditorStyles.label.CalcSize(new GUIContent("Value")).x; + var valueWidth = EditorStyles.textField.CalcSize(new GUIContent($"{lampIdValue.value}")).x; + + position = BeginLabeledBlock(metadata, position, label); + + var fieldPosition = position.VerticalSection(ref y, GetFieldHeight(position.width, GUIContent.none)); + + var textFieldPosition = new Rect + ( + fieldPosition.x, + fieldPosition.y, + fieldPosition.width - valueWidth - LabelPadding - valueLabelWidth - LabelPadding - Styles.popup.fixedWidth, + fieldPosition.height + ); + + var popupPosition = new Rect + ( + textFieldPosition.xMax, + fieldPosition.y, + Styles.popup.fixedWidth, + fieldPosition.height + ); + + var newIdValue = EditorGUI.TextField(textFieldPosition, lampIdValue.id, Styles.textField); + + // Micro optimizing memory here because it's a pretty substantial alloc + + suggestions.Clear(); + suggestions.AddRange(getSuggestions()); + + EditorGUI.BeginDisabledGroup(suggestions.Count == 0); + + var suggestionsArray = getSuggestions().ToArray(); + var currentSuggestionIndex = Array.IndexOf(suggestionsArray, lampIdValue.id); + + EditorGUI.BeginChangeCheck(); + + var newSuggestionIndex = EditorGUI.Popup(popupPosition, currentSuggestionIndex, suggestionsArray, Styles.popup); + + if (EditorGUI.EndChangeCheck()) + { + newIdValue = suggestions[newSuggestionIndex]; + } + + EditorGUI.EndDisabledGroup(); + + var valueLabelPosition = new Rect + ( + fieldPosition.x + fieldPosition.width - valueWidth - LabelPadding - valueLabelWidth, + fieldPosition.y, + valueLabelWidth, + fieldPosition.height + ); + + EditorGUI.LabelField(valueLabelPosition, "Value"); + + var valueIntFieldPosition = new Rect + ( + fieldPosition.x + fieldPosition.width - valueWidth, + fieldPosition.y, + valueWidth, + fieldPosition.height + ); + + var newValue = LudiqGUI.DraggableIntField(valueIntFieldPosition, lampIdValue.value); + + if (EndBlock(metadata)) + { + metadata.RecordUndo(); + + lampIdValue.id = newIdValue; + lampIdValue.value = newValue; + + metadata.value = lampIdValue.ToJson(); + } + } + + public override float GetAdaptiveWidth() + { + LampIdValue lampIdValue = LampIdValue.FromJson((string)metadata.value); + + return Mathf.Max(30, + EditorStyles.textField.CalcSize(new GUIContent(lampIdValue.id)).x + 1 + Styles.popup.fixedWidth) + + LabelPadding + + EditorStyles.label.CalcSize(new GUIContent("Value")).x + + LabelPadding + + EditorStyles.textField.CalcSize(new GUIContent($"{lampIdValue.value}")).x; + } + + public static class Styles + { + static Styles() + { + textField = new GUIStyle(EditorStyles.textField); + + popup = new GUIStyle("TextFieldDropDown"); + popup.fixedWidth = 18; + popup.clipping = TextClipping.Clip; + popup.normal.textColor = ColorPalette.transparent; + popup.active.textColor = ColorPalette.transparent; + popup.hover.textColor = ColorPalette.transparent; + popup.focused.textColor = ColorPalette.transparent; + popup.onNormal.textColor = ColorPalette.transparent; + popup.onActive.textColor = ColorPalette.transparent; + popup.onHover.textColor = ColorPalette.transparent; + popup.onFocused.textColor = ColorPalette.transparent; + } + + public static readonly GUIStyle textField; + public static readonly GUIStyle popup; + } + } +} diff --git a/Editor/Inspectors/LampIdValueInspector.cs.meta b/Editor/Inspectors/LampIdValueInspector.cs.meta new file mode 100644 index 0000000..7d0de85 --- /dev/null +++ b/Editor/Inspectors/LampIdValueInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1d13acec859f34990b640564525464c5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Inspectors/VariableDefinitionInspector.cs b/Editor/Inspectors/VariableDefinitionInspector.cs new file mode 100644 index 0000000..f8ee145 --- /dev/null +++ b/Editor/Inspectors/VariableDefinitionInspector.cs @@ -0,0 +1,103 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System.Collections.Generic; +using System.Linq; +using Unity.VisualScripting; +using UnityEditor; +using UnityEngine; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Inspector(typeof(PlayerVariableDefinition))] + public class PlayerVariableDefinitionInspector : VariableDefinitionInspector + { + public PlayerVariableDefinitionInspector(Metadata metadata) : base(metadata) + { + } + + protected override List VariableDefinition(VisualScriptingGamelogicEngine gle) + { + return gle.PlayerVariableDefinitions.Select(s => s as VariableDefinition).ToList(); + } + } + + [Inspector(typeof(TableVariableDefinition))] + public class TableVariableDefinitionInspector : VariableDefinitionInspector + { + public TableVariableDefinitionInspector(Metadata metadata) : base(metadata) + { + } + + protected override List VariableDefinition(VisualScriptingGamelogicEngine gle) + { + return gle.TableVariableDefinitions.Select(s => s as VariableDefinition).ToList(); + } + } + + public abstract class VariableDefinitionInspector : GleInspector + { + protected abstract List VariableDefinition(VisualScriptingGamelogicEngine gle); + + public VariableDefinitionInspector(Metadata metadata) : base(metadata) { } + + protected override void OnGUI(Rect position, GUIContent label) + { + // can't get this from the flow + var gle = Gle; + if (gle != null) { + var varDefinitions = VariableDefinition(gle); + if (varDefinitions == null || varDefinitions.Count(p => !string.IsNullOrEmpty(p.Name)) == 0) { + ErrorMessage = "No variables defined."; + + } else { + var varNames = new List { "None" } + .Concat(varDefinitions.Select(d => d.Name)) + .ToArray(); + var currentVarDef = metadata.value as VariableDefinition; + var currentIndex = 0; + if (currentVarDef != null) { + var stateVarDef = varDefinitions.FirstOrDefault(p => p.Id == currentVarDef!.Id); + currentIndex = stateVarDef != null ? varDefinitions.IndexOf(stateVarDef) + 1 : 0; + } + + var newIndex = EditorGUI.Popup(position, currentIndex, varNames); + metadata.RecordUndo(); + metadata.value = newIndex == 0 ? null : varDefinitions[newIndex - 1]; + ErrorMessage = null; + } + } + + if (ErrorMessage != null) { + position.height -= EditorGUIUtility.standardVerticalSpacing; + EditorGUI.HelpBox(position, ErrorMessage, MessageType.Error); + } + } + + public override float GetAdaptiveWidth() => LudiqGUIUtility.currentInspectorWidth; + + protected override float GetHeight(float width, GUIContent label) + { + if (ErrorMessage != null) { + var height = LudiqGUIUtility.GetHelpBoxHeight(ErrorMessage, MessageType.Error, width); + height += EditorGUIUtility.standardVerticalSpacing; + return height; + } + + return EditorGUIUtility.singleLineHeight; + } + } +} diff --git a/Editor/Inspectors/VariableDefinitionInspector.cs.meta b/Editor/Inspectors/VariableDefinitionInspector.cs.meta new file mode 100644 index 0000000..71587cf --- /dev/null +++ b/Editor/Inspectors/VariableDefinitionInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5d4e39d70aaead34bab0655647cd1763 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Inspectors/VisualScriptingGamelogicEngineInspector.cs b/Editor/Inspectors/VisualScriptingGamelogicEngineInspector.cs new file mode 100644 index 0000000..a789460 --- /dev/null +++ b/Editor/Inspectors/VisualScriptingGamelogicEngineInspector.cs @@ -0,0 +1,109 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable AssignmentInConditionalExpression + +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; +using VisualPinball.Unity.Editor; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [CustomEditor(typeof(VisualScriptingGamelogicEngine))] + public class VisualScriptingGamelogicEngineInspector : BaseEditor + { + private VisualScriptingGamelogicEngine _gle; + private SerializedProperty _displaysProperty; + private SerializedProperty _switchesProperty; + private SerializedProperty _soilsProperty; + private SerializedProperty _lampsProperty; + private SerializedProperty _tableVariableDefinitionsProperty; + private SerializedProperty _playerVariableDefinitionsProperty; + private SerializedProperty _eventDefinitionsProperty; + + private readonly Dictionary _playerVarFoldout = new(); + + private void OnEnable() + { + _gle = target as VisualScriptingGamelogicEngine; + + _displaysProperty = serializedObject.FindProperty(nameof(VisualScriptingGamelogicEngine.Displays)); + _switchesProperty = serializedObject.FindProperty(nameof(VisualScriptingGamelogicEngine.Switches)); + _soilsProperty = serializedObject.FindProperty(nameof(VisualScriptingGamelogicEngine.Coils)); + _lampsProperty = serializedObject.FindProperty(nameof(VisualScriptingGamelogicEngine.Lamps)); + + _tableVariableDefinitionsProperty = serializedObject.FindProperty(nameof(VisualScriptingGamelogicEngine.TableVariableDefinitions)); + _playerVariableDefinitionsProperty = serializedObject.FindProperty(nameof(VisualScriptingGamelogicEngine.PlayerVariableDefinitions)); + + _eventDefinitionsProperty = serializedObject.FindProperty(nameof(VisualScriptingGamelogicEngine.EventDefinitions)); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.PropertyField(_displaysProperty); + EditorGUILayout.PropertyField(_switchesProperty); + EditorGUILayout.PropertyField(_soilsProperty); + EditorGUILayout.PropertyField(_lampsProperty); + + EditorGUILayout.PropertyField(_tableVariableDefinitionsProperty); + EditorGUILayout.PropertyField(_playerVariableDefinitionsProperty); + EditorGUILayout.PropertyField(_eventDefinitionsProperty); + + serializedObject.ApplyModifiedProperties(); + + // what follows is runtime data + if (!Application.isPlaying) { + return; + } + + EditorGUILayout.TextField("Table Variables", new GUIStyle(EditorStyles.boldLabel)); + PrintState(_gle.TableState, _gle.TableVariableDefinitions); + + if (_gle.PlayerStates.Count == 0) { + EditorGUILayout.HelpBox("No player states created.", MessageType.Info); + return; + } + + EditorGUILayout.TextField("Player States", new GUIStyle(EditorStyles.boldLabel)); + foreach (var playerId in _gle.PlayerStates.Keys) { + if (!_playerVarFoldout.ContainsKey(playerId)) { + _playerVarFoldout[playerId] = true; + } + if (_playerVarFoldout[playerId] = EditorGUILayout.BeginFoldoutHeaderGroup(_playerVarFoldout[playerId], $"Player {playerId}")) { + EditorGUI.indentLevel++; + + if (_gle.CurrentPlayerState == _gle.PlayerStates[playerId]) { + EditorGUILayout.HelpBox("Current Player", MessageType.Info); + } + + PrintState(_gle.PlayerStates[playerId], _gle.PlayerVariableDefinitions); + EditorGUI.indentLevel--; + } + EditorGUILayout.EndFoldoutHeaderGroup(); + } + } + + private static void PrintState(State state, IEnumerable definitions) + { + foreach (var varDef in definitions) { + EditorGUILayout.LabelField(varDef.Name, state.Get(varDef.Id).ToString()); + } + } + } +} diff --git a/Editor/Inspectors/VisualScriptingGamelogicEngineInspector.cs.meta b/Editor/Inspectors/VisualScriptingGamelogicEngineInspector.cs.meta new file mode 100644 index 0000000..aca104f --- /dev/null +++ b/Editor/Inspectors/VisualScriptingGamelogicEngineInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7e81903d0a4e88c4ca26c9f902f6d247 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PropertyDrawers/DisplayDefinitionPropertyDrawer.cs b/Editor/PropertyDrawers/DisplayDefinitionPropertyDrawer.cs new file mode 100644 index 0000000..cfffc74 --- /dev/null +++ b/Editor/PropertyDrawers/DisplayDefinitionPropertyDrawer.cs @@ -0,0 +1,93 @@ +// // Visual Pinball Engine +// // Copyright (C) 2022 freezy and VPE Team +// // +// // This program is free software: you can redistribute it and/or modify +// // it under the terms of the GNU General Public License as published by +// // the Free Software Foundation, either version 3 of the License, or +// // (at your option) any later version. +// // +// // This program is distributed in the hope that it will be useful, +// // but WITHOUT ANY WARRANTY; without even the implied warranty of +// // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// // GNU General Public License for more details. +// // +// // You should have received a copy of the GNU General Public License +// // along with this program. If not, see . +// +// using UnityEditor; +// using UnityEngine; +// +// namespace VisualPinball.Unity.VisualScripting.Editor +// { +// [CustomPropertyDrawer(typeof(DisplayDefinition))] +// public class DisplayDefinitionPropertyDrawer : PropertyDrawer +// { +// private const float Padding = 2f; +// +// public override float GetPropertyHeight(SerializedProperty property, GUIContent label) +// { +// return base.GetPropertyHeight(property, label); +// // var f = property.FindPropertyRelative(nameof(DisplayDefinition.SupportedFormats)); +// // +// // return 5 * (EditorGUIUtility.singleLineHeight + Padding); +// } +// +// public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) +// { +// var idProperty = property.FindPropertyRelative(nameof(DisplayDefinition.Id)); +// var widthProperty = property.FindPropertyRelative(nameof(DisplayDefinition.Width)); +// var heightProperty = property.FindPropertyRelative(nameof(DisplayDefinition.Height)); +// +// var contentPosition = position; +// contentPosition.height = EditorGUIUtility.singleLineHeight; +// +// //EditorGUI.BeginProperty(position, label, property); +// EditorGUI.PropertyField(contentPosition, idProperty, new GUIContent("ID:")); +// //EditorGUI.EndProperty(); +// position.y += EditorGUIUtility.singleLineHeight + Padding; +// +// contentPosition = EditorGUI.PrefixLabel(position, new GUIContent("Size:")); +// contentPosition.height = EditorGUIUtility.singleLineHeight; +// +// var half = contentPosition.width / 2; +// GUI.skin.label.padding = new RectOffset(3, 3, 6, 6); +// +// //show the X and Y from the point +// var oldLabelWidth = EditorGUIUtility.labelWidth; +// EditorGUIUtility.labelWidth = 14f; +// contentPosition.width *= 0.5f; +// EditorGUI.indentLevel = 0; +// +// // Begin/end property & change check make each field +// // behave correctly when multi-object editing. +// EditorGUI.BeginProperty(contentPosition, label, widthProperty); +// { +// EditorGUI.BeginChangeCheck(); +// var newVal = EditorGUI.IntField(contentPosition, new GUIContent("W"), widthProperty.intValue); +// if (EditorGUI.EndChangeCheck()) +// widthProperty.intValue = newVal; +// } +// EditorGUI.EndProperty(); +// +// contentPosition.x += half; +// EditorGUI.BeginProperty(contentPosition, label, heightProperty); +// { +// EditorGUI.BeginChangeCheck(); +// var newVal = EditorGUI.IntField(contentPosition, new GUIContent("H"), heightProperty.intValue); +// if (EditorGUI.EndChangeCheck()) +// heightProperty.intValue = newVal; +// } +// EditorGUI.EndProperty(); +// +// EditorGUIUtility.labelWidth = oldLabelWidth; +// +// var supportedFormatsProperty = property.FindPropertyRelative(nameof(DisplayDefinition.SupportedFormats)); +// +// position.y += EditorGUIUtility.singleLineHeight + Padding; +// contentPosition = position; +// contentPosition.height = EditorGUIUtility.singleLineHeight; +// EditorGUI.PropertyField(contentPosition, supportedFormatsProperty, new GUIContent("Supported Formats:")); +// } +// } +// } +// diff --git a/Editor/PropertyDrawers/DisplayDefinitionPropertyDrawer.cs.meta b/Editor/PropertyDrawers/DisplayDefinitionPropertyDrawer.cs.meta new file mode 100644 index 0000000..b9820d0 --- /dev/null +++ b/Editor/PropertyDrawers/DisplayDefinitionPropertyDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d6182e48489a56a49a67f3841551a094 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PropertyDrawers/EventDefinitionPropertyDrawer.cs b/Editor/PropertyDrawers/EventDefinitionPropertyDrawer.cs new file mode 100644 index 0000000..bd65d10 --- /dev/null +++ b/Editor/PropertyDrawers/EventDefinitionPropertyDrawer.cs @@ -0,0 +1,44 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using UnityEditor; +using UnityEngine; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [CustomPropertyDrawer(typeof(EventDefinition))] + public class EventDefinitionPropertyDrawer : PropertyDrawer + { + private const float Padding = 2f; + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return EditorGUIUtility.singleLineHeight + Padding; + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + EditorGUI.BeginProperty(position, label, property); + + var nameProperty = property.FindPropertyRelative(nameof(EventDefinition.Name)); + position.height = EditorGUIUtility.singleLineHeight; + EditorGUI.PropertyField(position, nameProperty); + + EditorGUI.EndProperty(); + } + } +} + diff --git a/Editor/PropertyDrawers/EventDefinitionPropertyDrawer.cs.meta b/Editor/PropertyDrawers/EventDefinitionPropertyDrawer.cs.meta new file mode 100644 index 0000000..d6224d4 --- /dev/null +++ b/Editor/PropertyDrawers/EventDefinitionPropertyDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fa3eade119d9f714c8bdfa28b37ad69f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PropertyDrawers/VariableDefinitionPropertyDrawer.cs b/Editor/PropertyDrawers/VariableDefinitionPropertyDrawer.cs new file mode 100644 index 0000000..97c7365 --- /dev/null +++ b/Editor/PropertyDrawers/VariableDefinitionPropertyDrawer.cs @@ -0,0 +1,80 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using UnityEditor; +using UnityEngine; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [CustomPropertyDrawer(typeof(PlayerVariableDefinition))] + public class PlayerVariableDefinitionPropertyDrawer : VariableDefinitionPropertyDrawer + { + } + + [CustomPropertyDrawer(typeof(TableVariableDefinition))] + public class TableVariableDefinitionPropertyDrawer : VariableDefinitionPropertyDrawer + { + } + + public class VariableDefinitionPropertyDrawer : PropertyDrawer + { + private const float Padding = 2f; + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return 3 * (EditorGUIUtility.singleLineHeight + Padding); + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + EditorGUI.BeginProperty(position, label, property); + + var nameProperty = property.FindPropertyRelative(nameof(VariableDefinition.Name)); + var typeProperty = property.FindPropertyRelative(nameof(VariableDefinition.Type)); + var typeIndex = typeProperty.enumValueIndex; + + SerializedProperty valueProp; + switch (typeIndex) { + case (int)VariableType.String: + valueProp = property.FindPropertyRelative(nameof(VariableDefinition.StringDefaultValue)); + break; + case (int)VariableType.Integer: + valueProp = property.FindPropertyRelative(nameof(VariableDefinition.IntegerDefaultValue)); + break; + case (int)VariableType.Float: + valueProp = property.FindPropertyRelative(nameof(VariableDefinition.FloatDefaultValue)); + break; + case (int)VariableType.Boolean: + valueProp = property.FindPropertyRelative(nameof(VariableDefinition.BooleanDefaultValue)); + break; + default: + throw new ArgumentException($"Undefined type index {typeIndex}."); + } + + position.height = EditorGUIUtility.singleLineHeight; + + EditorGUI.PropertyField(position, nameProperty, new GUIContent("Name:")); + position.y += EditorGUIUtility.singleLineHeight + Padding; + EditorGUI.PropertyField(position, typeProperty, new GUIContent("Type:")); + position.y += EditorGUIUtility.singleLineHeight + Padding; + EditorGUI.PropertyField(position, valueProp, new GUIContent("Initial Value:")); + + EditorGUI.EndProperty(); + } + } +} + diff --git a/Editor/PropertyDrawers/VariableDefinitionPropertyDrawer.cs.meta b/Editor/PropertyDrawers/VariableDefinitionPropertyDrawer.cs.meta new file mode 100644 index 0000000..c791c5e --- /dev/null +++ b/Editor/PropertyDrawers/VariableDefinitionPropertyDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d6dd518bc4a998c488368c470a50a39a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Widgets/AllCoilsEnabledEventUnitWidget.cs b/Editor/Widgets/AllCoilsEnabledEventUnitWidget.cs new file mode 100644 index 0000000..7c2ea40 --- /dev/null +++ b/Editor/Widgets/AllCoilsEnabledEventUnitWidget.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using System.Linq; +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Widget(typeof(AllCoilsEnabledEventUnit))] + public sealed class AllCoilsEnabledEventUnitWidget : GleMultiUnitWidget + { + public AllCoilsEnabledEventUnitWidget(FlowCanvas canvas, AllCoilsEnabledEventUnit unit) : base(canvas, unit) + { + } + + protected override IEnumerable IdSuggestions(IGamelogicEngine gle) => gle.RequestedCoils.Select(coil => coil.Id); + } +} diff --git a/Editor/Widgets/AllCoilsEnabledEventUnitWidget.cs.meta b/Editor/Widgets/AllCoilsEnabledEventUnitWidget.cs.meta new file mode 100644 index 0000000..d66e2c9 --- /dev/null +++ b/Editor/Widgets/AllCoilsEnabledEventUnitWidget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bf621aacfaf6b4110bcc52feafa48776 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Widgets/AllSwitchesEnabledEventUnitWidget.cs b/Editor/Widgets/AllSwitchesEnabledEventUnitWidget.cs new file mode 100644 index 0000000..3bd4bb5 --- /dev/null +++ b/Editor/Widgets/AllSwitchesEnabledEventUnitWidget.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using System.Linq; +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Widget(typeof(AllSwitchesEnabledEventUnit))] + public sealed class AllSwitchesEnabledEventUnitWidget : GleMultiUnitWidget + { + public AllSwitchesEnabledEventUnitWidget(FlowCanvas canvas, AllSwitchesEnabledEventUnit unit) : base(canvas, unit) + { + } + + protected override IEnumerable IdSuggestions(IGamelogicEngine gle) => gle.RequestedSwitches.Select(sw => sw.Id); + } +} diff --git a/Editor/Widgets/AllSwitchesEnabledEventUnitWidget.cs.meta b/Editor/Widgets/AllSwitchesEnabledEventUnitWidget.cs.meta new file mode 100644 index 0000000..728d748 --- /dev/null +++ b/Editor/Widgets/AllSwitchesEnabledEventUnitWidget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7872e03c03543244594aa193847f285e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Widgets/ChangePlayerStateUnitWidget.cs b/Editor/Widgets/ChangePlayerStateUnitWidget.cs new file mode 100644 index 0000000..1a460fa --- /dev/null +++ b/Editor/Widgets/ChangePlayerStateUnitWidget.cs @@ -0,0 +1,30 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Widget(typeof(ChangePlayerStateUnit))] + public sealed class ChangePlayerStateUnitWidget : GleUnitWidget + { + public ChangePlayerStateUnitWidget(FlowCanvas canvas, ChangePlayerStateUnit unit) : base(canvas, unit) + { + } + } +} diff --git a/Editor/Widgets/ChangePlayerStateUnitWidget.cs.meta b/Editor/Widgets/ChangePlayerStateUnitWidget.cs.meta new file mode 100644 index 0000000..4c83cca --- /dev/null +++ b/Editor/Widgets/ChangePlayerStateUnitWidget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fd85a3e9145ab0e4ab4da48948b23eb2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Widgets/CoilEnabledEventUnitWidget.cs b/Editor/Widgets/CoilEnabledEventUnitWidget.cs new file mode 100644 index 0000000..378d20d --- /dev/null +++ b/Editor/Widgets/CoilEnabledEventUnitWidget.cs @@ -0,0 +1,34 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using System.Collections.Generic; +using System.Linq; +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Widget(typeof(CoilEnabledEventUnit))] + public sealed class CoilEnabledEventUnitWidget : GleMultiUnitWidget + { + public CoilEnabledEventUnitWidget(FlowCanvas canvas, CoilEnabledEventUnit unit) : base(canvas, unit) + { + } + + protected override IEnumerable IdSuggestions(IGamelogicEngine gle) => gle.RequestedCoils.Select(coil => coil.Id); + } +} diff --git a/Editor/Widgets/CoilEnabledEventUnitWidget.cs.meta b/Editor/Widgets/CoilEnabledEventUnitWidget.cs.meta new file mode 100644 index 0000000..bbd55f0 --- /dev/null +++ b/Editor/Widgets/CoilEnabledEventUnitWidget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6538db966e0994d1ebd1721fd65a9383 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Widgets/CoilEventUnitWidget.cs b/Editor/Widgets/CoilEventUnitWidget.cs new file mode 100644 index 0000000..2736b3b --- /dev/null +++ b/Editor/Widgets/CoilEventUnitWidget.cs @@ -0,0 +1,34 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using System.Collections.Generic; +using System.Linq; +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Widget(typeof(CoilEventUnit))] + public sealed class CoilEventUnitWidget : GleMultiUnitWidget + { + public CoilEventUnitWidget(FlowCanvas canvas, CoilEventUnit unit) : base(canvas, unit) + { + } + + protected override IEnumerable IdSuggestions(IGamelogicEngine gle) => gle.RequestedCoils.Select(coil => coil.Id); + } +} diff --git a/Editor/Widgets/CoilEventUnitWidget.cs.meta b/Editor/Widgets/CoilEventUnitWidget.cs.meta new file mode 100644 index 0000000..f9bd8a0 --- /dev/null +++ b/Editor/Widgets/CoilEventUnitWidget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3ef4988f2d47743e295807077993a949 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Widgets/CreateBallUnitWidget.cs b/Editor/Widgets/CreateBallUnitWidget.cs new file mode 100644 index 0000000..951094f --- /dev/null +++ b/Editor/Widgets/CreateBallUnitWidget.cs @@ -0,0 +1,33 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using System; +using System.Collections.Generic; +using System.Linq; +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Widget(typeof(CreateBallUnit))] + public sealed class CreateBallUnitWidget : GleUnitWidget + { + public CreateBallUnitWidget(FlowCanvas canvas, CreateBallUnit unit) : base(canvas, unit) + { + } + } +} diff --git a/Editor/Widgets/CreateBallUnitWidget.cs.meta b/Editor/Widgets/CreateBallUnitWidget.cs.meta new file mode 100644 index 0000000..363b76f --- /dev/null +++ b/Editor/Widgets/CreateBallUnitWidget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fb3210b2787102a46b94ecc9b9506e7a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Widgets/CreatePlayerStateUnitWidget.cs b/Editor/Widgets/CreatePlayerStateUnitWidget.cs new file mode 100644 index 0000000..4f9ae05 --- /dev/null +++ b/Editor/Widgets/CreatePlayerStateUnitWidget.cs @@ -0,0 +1,30 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Widget(typeof(CreatePlayerStateUnit))] + public sealed class CreatePlayerStateUnitWidget : GleUnitWidget + { + public CreatePlayerStateUnitWidget(FlowCanvas canvas, CreatePlayerStateUnit unit) : base(canvas, unit) + { + } + } +} diff --git a/Editor/Widgets/CreatePlayerStateUnitWidget.cs.meta b/Editor/Widgets/CreatePlayerStateUnitWidget.cs.meta new file mode 100644 index 0000000..3fb12e1 --- /dev/null +++ b/Editor/Widgets/CreatePlayerStateUnitWidget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f5f89faf861c39f4eb877a19ee7944af +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Widgets/SetLightUnitWidget.cs b/Editor/Widgets/GetCoilUnitWidget.cs similarity index 54% rename from Editor/Widgets/SetLightUnitWidget.cs rename to Editor/Widgets/GetCoilUnitWidget.cs index 9043f95..787212e 100644 --- a/Editor/Widgets/SetLightUnitWidget.cs +++ b/Editor/Widgets/GetCoilUnitWidget.cs @@ -17,30 +17,39 @@ // ReSharper disable UnusedType.Global using System; +using System.Collections.Generic; +using System.Linq; using Unity.VisualScripting; namespace VisualPinball.Unity.VisualScripting.Editor { - [Widget(typeof(SetLightUnit))] - public sealed class SetLightUnitWidget : UnitWidget + [Widget(typeof(GetCoilUnit))] + public sealed class GetCoilUnitWidget : GleUnitWidget { - private ObjectPickerInspector _objectInspector; - private readonly Func> _setObjectInspectorConstructor; - - public SetLightUnitWidget(FlowCanvas canvas, SetLightUnit unit) : base(canvas, unit) + public GetCoilUnitWidget(FlowCanvas canvas, GetCoilUnit unit) : base(canvas, unit) { - var tc = reference.gameObject.GetComponentInParent(); - _setObjectInspectorConstructor = meta => new ObjectPickerInspector(meta, "Lamps", tc); + _coilIdInspectorConstructor = meta => new VariableNameInspector(meta, GetNameSuggestions); } + private VariableNameInspector _coilIdInspector; + private readonly Func _coilIdInspectorConstructor; + public override Inspector GetPortInspector(IUnitPort port, Metadata meta) { - if (port == unit.LampComponent) { - InspectorProvider.instance.Renew(ref _objectInspector, meta, _setObjectInspectorConstructor); - return _objectInspector; + if (port == unit.Id) { + InspectorProvider.instance.Renew(ref _coilIdInspector, meta, _coilIdInspectorConstructor); + + return _coilIdInspector; } + return base.GetPortInspector(port, meta); } + private IEnumerable GetNameSuggestions() + { + return !GleAvailable + ? new List() + : Gle.RequestedCoils.Select(coil => coil.Id).ToList(); + } } } diff --git a/Editor/Widgets/GetCoilUnitWidget.cs.meta b/Editor/Widgets/GetCoilUnitWidget.cs.meta new file mode 100644 index 0000000..6e41f12 --- /dev/null +++ b/Editor/Widgets/GetCoilUnitWidget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c1bfda7a60fc04ad79ac234b8458fdeb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Widgets/GetLampUnitWidget.cs b/Editor/Widgets/GetLampUnitWidget.cs index 4a99b9f..2372846 100644 --- a/Editor/Widgets/GetLampUnitWidget.cs +++ b/Editor/Widgets/GetLampUnitWidget.cs @@ -31,8 +31,6 @@ public GetLampUnitWidget(FlowCanvas canvas, GetLampUnit unit) : base(canvas, uni _lampIdInspectorConstructor = meta => new VariableNameInspector(meta, GetNameSuggestions); } - protected override NodeColorMix baseColor => NodeColorMix.TealReadable; - private VariableNameInspector _lampIdInspector; private readonly Func _lampIdInspectorConstructor; @@ -49,11 +47,9 @@ public override Inspector GetPortInspector(IUnitPort port, Metadata meta) private IEnumerable GetNameSuggestions() { - if (!GameObjectAvailable) { - return new List(); - } - var gle = Gle; - return gle == null ? new List() : gle.AvailableLamps.Select(lamp => lamp.Id).ToList(); + return !GleAvailable + ? new List() + : Gle.RequestedLamps.Select(lamp => lamp.Id).ToList(); } } } diff --git a/Editor/Widgets/GetPlayerIdWidget.cs b/Editor/Widgets/GetPlayerIdWidget.cs new file mode 100644 index 0000000..5c4a8f2 --- /dev/null +++ b/Editor/Widgets/GetPlayerIdWidget.cs @@ -0,0 +1,30 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Widget(typeof(GetPlayerIdUnit))] + public sealed class GetPlayerIdWidget : GleUnitWidget + { + public GetPlayerIdWidget(FlowCanvas canvas, GetPlayerIdUnit unit) : base(canvas, unit) + { + } + } +} diff --git a/Editor/Widgets/GetPlayerIdWidget.cs.meta b/Editor/Widgets/GetPlayerIdWidget.cs.meta new file mode 100644 index 0000000..0727cfb --- /dev/null +++ b/Editor/Widgets/GetPlayerIdWidget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 95515a3dee20c4e48b35018c852d635a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Widgets/SetLightSequenceUnitWidget.cs b/Editor/Widgets/GetSwitchUnitWidget.cs similarity index 53% rename from Editor/Widgets/SetLightSequenceUnitWidget.cs rename to Editor/Widgets/GetSwitchUnitWidget.cs index a316ce8..e570448 100644 --- a/Editor/Widgets/SetLightSequenceUnitWidget.cs +++ b/Editor/Widgets/GetSwitchUnitWidget.cs @@ -17,29 +17,39 @@ // ReSharper disable UnusedType.Global using System; +using System.Collections.Generic; +using System.Linq; using Unity.VisualScripting; namespace VisualPinball.Unity.VisualScripting.Editor { - [Widget(typeof(SetLightSequenceUnit))] - public sealed class SetLightSequenceUnitWidget : UnitWidget + [Widget(typeof(GetSwitchUnit))] + public sealed class GetSwitchUnitWidget : GleUnitWidget { - private ObjectPickerInspector _objectInspector; - private readonly Func> _setObjectInspectorConstructor; - - public SetLightSequenceUnitWidget(FlowCanvas canvas, SetLightSequenceUnit unit) : base(canvas, unit) + public GetSwitchUnitWidget(FlowCanvas canvas, GetSwitchUnit unit) : base(canvas, unit) { - var tc = reference.gameObject.GetComponentInParent(); - _setObjectInspectorConstructor = meta => new ObjectPickerInspector(meta, "Light Groups", tc); + _switchIdInspectorConstructor = meta => new VariableNameInspector(meta, GetNameSuggestions); } + private VariableNameInspector _switchIdInspector; + private readonly Func _switchIdInspectorConstructor; + public override Inspector GetPortInspector(IUnitPort port, Metadata meta) { - if (port == unit.LightGroup) { - InspectorProvider.instance.Renew(ref _objectInspector, meta, _setObjectInspectorConstructor); - return _objectInspector; + if (port == unit.Id) { + InspectorProvider.instance.Renew(ref _switchIdInspector, meta, _switchIdInspectorConstructor); + + return _switchIdInspector; } + return base.GetPortInspector(port, meta); } + + private IEnumerable GetNameSuggestions() + { + return !GleAvailable + ? new List() + : Gle.RequestedSwitches.Select(sw => sw.Id).ToList(); + } } } diff --git a/Editor/Widgets/GetSwitchUnitWidget.cs.meta b/Editor/Widgets/GetSwitchUnitWidget.cs.meta new file mode 100644 index 0000000..d09f2bb --- /dev/null +++ b/Editor/Widgets/GetSwitchUnitWidget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b7d886023af764b62b6ca54f024a1e0a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Widgets/GetVariableUnitWidget.cs b/Editor/Widgets/GetVariableUnitWidget.cs new file mode 100644 index 0000000..ef7e0f3 --- /dev/null +++ b/Editor/Widgets/GetVariableUnitWidget.cs @@ -0,0 +1,38 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Widget(typeof(GetPlayerVariableUnit))] + public sealed class GetPlayerVariableUnitWidget : GleUnitWidget + { + public GetPlayerVariableUnitWidget(FlowCanvas canvas, GetPlayerVariableUnit unit) : base(canvas, unit) + { + } + } + + [Widget(typeof(GetTableVariableUnit))] + public sealed class GetTableVariableUnitWidget : GleUnitWidget + { + public GetTableVariableUnitWidget(FlowCanvas canvas, GetTableVariableUnit unit) : base(canvas, unit) + { + } + } +} diff --git a/Editor/Widgets/GetVariableUnitWidget.cs.meta b/Editor/Widgets/GetVariableUnitWidget.cs.meta new file mode 100644 index 0000000..ab8b8e0 --- /dev/null +++ b/Editor/Widgets/GetVariableUnitWidget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5cfa006a94c6fbf46ae5d3b199a9603e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Widgets/GleMultiUnitWidget.cs b/Editor/Widgets/GleMultiUnitWidget.cs new file mode 100644 index 0000000..d4ee88d --- /dev/null +++ b/Editor/Widgets/GleMultiUnitWidget.cs @@ -0,0 +1,60 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.Collections.Generic; +using System.Linq; +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + public abstract class GleMultiUnitWidget : GleUnitWidget where TUnit : Unit, IGleUnit, IMultiInputUnit + { + protected abstract IEnumerable IdSuggestions(IGamelogicEngine gle); + + private readonly List> _idInspectorConstructorList; + + protected GleMultiUnitWidget(FlowCanvas canvas, TUnit unit) : base(canvas, unit) + { + _idInspectorConstructorList = new List>(); + } + + public override Inspector GetPortInspector(IUnitPort port, Metadata meta) + { + if (_idInspectorConstructorList.Count < unit.inputCount) { + for (var index = 0; index < unit.inputCount - _idInspectorConstructorList.Count(); index++) { + _idInspectorConstructorList.Add(m => new VariableNameInspector(m, GetNameSuggestions)); + } + } + + for (var index = 0; index < unit.inputCount; index++) { + if (unit.multiInputs[index] == port) { + var idInspector = new VariableNameInspector(meta, GetNameSuggestions); + InspectorProvider.instance.Renew(ref idInspector, meta, _idInspectorConstructorList[index]); + + return idInspector; + } + } + + return base.GetPortInspector(port, meta); + } + + private IEnumerable GetNameSuggestions() + { + return !GleAvailable ? new List() : IdSuggestions(Gle).ToList(); + } + } +} diff --git a/Editor/Widgets/GleMultiUnitWidget.cs.meta b/Editor/Widgets/GleMultiUnitWidget.cs.meta new file mode 100644 index 0000000..a0d1884 --- /dev/null +++ b/Editor/Widgets/GleMultiUnitWidget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fe225b58cd15fa94fb99874e34e616f5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Widgets/GleStartedEventUnitWidget.cs b/Editor/Widgets/GleStartedEventUnitWidget.cs new file mode 100644 index 0000000..dacf921 --- /dev/null +++ b/Editor/Widgets/GleStartedEventUnitWidget.cs @@ -0,0 +1,30 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Widget(typeof(GleStartedEventUnit))] + public sealed class GleStartedEventUnitWidget : GleUnitWidget + { + public GleStartedEventUnitWidget(FlowCanvas canvas, GleStartedEventUnit unit) : base(canvas, unit) + { + } + } +} diff --git a/Editor/Widgets/GleStartedEventUnitWidget.cs.meta b/Editor/Widgets/GleStartedEventUnitWidget.cs.meta new file mode 100644 index 0000000..e6bfd5d --- /dev/null +++ b/Editor/Widgets/GleStartedEventUnitWidget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 45080ca839581524da47bc355e4466b8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Widgets/GleUnitWidget.cs b/Editor/Widgets/GleUnitWidget.cs index 0cac6e6..89bb19d 100644 --- a/Editor/Widgets/GleUnitWidget.cs +++ b/Editor/Widgets/GleUnitWidget.cs @@ -15,23 +15,36 @@ // along with this program. If not, see . using Unity.VisualScripting; +using UnityEngine; namespace VisualPinball.Unity.VisualScripting.Editor { + public static class GleUnitWidget + { + public static readonly NodeColorMix Color = new() { + red = 0.92549019607843137254901960784314f, + green = 0.51764705882352941176470588235294f, + blue = 0.23921568627450980392156862745098f + }; + } + public abstract class GleUnitWidget : UnitWidget where TUnit : Unit, IGleUnit { - protected override NodeColorMix baseColor => GleAvailable ? NodeColorMix.TealReadable : new NodeColorMix { red = 1f, green = 0f, blue = 0f }; - protected bool GameObjectAvailable => reference != null && reference.gameObject != null; - protected IGamelogicEngine Gle => reference.gameObject.GetComponentInParent(); - private bool GleAvailable => GameObjectAvailable && Gle != null; + protected override NodeColorMix baseColor => GleAvailable ? GleUnitWidget.Color : NodeColor.Red; + protected IGamelogicEngine Gle; + protected VisualScriptingGamelogicEngine VsGle; + protected bool GleAvailable => Gle != null; + protected bool VsGleAvailable => VsGle != null; protected GleUnitWidget(FlowCanvas canvas, TUnit unit) : base(canvas, unit) { - if (!GameObjectAvailable) { - unit.Errors.Add("Not attached to GameObject. You need to attach this graph to a flow machine sitting on a GameObject in order to use it."); - - } else if (!GleAvailable) { - unit.Errors.Add("No gamelogic engine found. One of the GameObject's parents must have a gamelogic engine component."); + var table = TableSelector.Instance.SelectedOrFirstTable; + if (table != null) { + Gle = table.GetComponentInChildren(); + VsGle = table.GetComponentInChildren(); + } + if (!GleAvailable) { + Debug.LogError($"Cannot find GLE for {GetType()}."); } } } diff --git a/Editor/Widgets/IncreaseVariableUnitWidget.cs b/Editor/Widgets/IncreaseVariableUnitWidget.cs new file mode 100644 index 0000000..9d8766e --- /dev/null +++ b/Editor/Widgets/IncreaseVariableUnitWidget.cs @@ -0,0 +1,38 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Widget(typeof(IncreasePlayerVariableUnit))] + public sealed class IncreasePlayerVariableUnitWidget : GleUnitWidget + { + public IncreasePlayerVariableUnitWidget(FlowCanvas canvas, IncreasePlayerVariableUnit unit) : base(canvas, unit) + { + } + } + + [Widget(typeof(IncreaseTableVariableUnit))] + public sealed class IncreaseTableVariableUnitWidget : GleUnitWidget + { + public IncreaseTableVariableUnitWidget(FlowCanvas canvas, IncreaseTableVariableUnit unit) : base(canvas, unit) + { + } + } +} diff --git a/Editor/Widgets/IncreaseVariableUnitWidget.cs.meta b/Editor/Widgets/IncreaseVariableUnitWidget.cs.meta new file mode 100644 index 0000000..3703573 --- /dev/null +++ b/Editor/Widgets/IncreaseVariableUnitWidget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2d12ac9db2285cd408046a05dfba71b4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Widgets/LampEventUnitWidget.cs b/Editor/Widgets/LampEventUnitWidget.cs index fdba3f5..e733e60 100644 --- a/Editor/Widgets/LampEventUnitWidget.cs +++ b/Editor/Widgets/LampEventUnitWidget.cs @@ -1,60 +1,34 @@ -// Visual Pinball Engine -// Copyright (C) 2022 freezy and VPE Team -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -// ReSharper disable UnusedType.Global - -using System; -using System.Collections.Generic; -using System.Linq; -using Unity.VisualScripting; - -namespace VisualPinball.Unity.VisualScripting.Editor -{ - [Widget(typeof(LampEventUnit))] - public sealed class LampEventUnitWidget : GleUnitWidget - { - public LampEventUnitWidget(FlowCanvas canvas, LampEventUnit unit) : base(canvas, unit) - { - _lampIdInspectorConstructor = meta => new VariableNameInspector(meta, GetNameSuggestions); - } - - protected override NodeColorMix baseColor => NodeColorMix.TealReadable; - - private VariableNameInspector _lampIdInspector; - private readonly Func _lampIdInspectorConstructor; - - public override Inspector GetPortInspector(IUnitPort port, Metadata meta) - { - if (port == unit.Id) { - InspectorProvider.instance.Renew(ref _lampIdInspector, meta, _lampIdInspectorConstructor); - - return _lampIdInspector; - } - - return base.GetPortInspector(port, meta); - } - - private IEnumerable GetNameSuggestions() - { - if (!GameObjectAvailable) { - return new List(); - } - - var gle = Gle; - return gle == null ? new List() : gle.AvailableLamps.Select(lamp => lamp.Id).ToList(); - } - } -} +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using System.Collections.Generic; +using System.Linq; +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Widget(typeof(LampEventUnit))] + public sealed class LampEventUnitWidget : GleMultiUnitWidget + { + public LampEventUnitWidget(FlowCanvas canvas, LampEventUnit unit) : base(canvas, unit) + { + } + + protected override IEnumerable IdSuggestions(IGamelogicEngine gle) => gle.RequestedLamps.Select(lamp => lamp.Id); + } +} diff --git a/Editor/Widgets/LampSequenceUnitWidget.cs b/Editor/Widgets/LampSequenceUnitWidget.cs new file mode 100644 index 0000000..44e5d21 --- /dev/null +++ b/Editor/Widgets/LampSequenceUnitWidget.cs @@ -0,0 +1,34 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using System.Collections.Generic; +using System.Linq; +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Widget(typeof(LampSequenceUnit))] + public sealed class LampSequenceUnitWidget : GleMultiUnitWidget + { + public LampSequenceUnitWidget(FlowCanvas canvas, LampSequenceUnit unit) : base(canvas, unit) + { + } + + protected override IEnumerable IdSuggestions(IGamelogicEngine gle) => gle.RequestedLamps.Select(lamp => lamp.Id); + } +} diff --git a/Editor/Widgets/LampSequenceUnitWidget.cs.meta b/Editor/Widgets/LampSequenceUnitWidget.cs.meta new file mode 100644 index 0000000..bdec38c --- /dev/null +++ b/Editor/Widgets/LampSequenceUnitWidget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9361364ed5194461ab46a8c5e27e7916 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Widgets/PinballEventUnitWidget.cs b/Editor/Widgets/PinballEventUnitWidget.cs new file mode 100644 index 0000000..b3b1c71 --- /dev/null +++ b/Editor/Widgets/PinballEventUnitWidget.cs @@ -0,0 +1,34 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using System; +using System.Collections.Generic; +using System.Linq; +using Unity.VisualScripting; +using UnityEngine; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Widget(typeof(PinballEventUnit))] + public sealed class PinballEventUnitWidget : GleUnitWidget + { + public PinballEventUnitWidget(FlowCanvas canvas, PinballEventUnit unit) : base(canvas, unit) + { + } + } +} diff --git a/Editor/Widgets/PinballEventUnitWidget.cs.meta b/Editor/Widgets/PinballEventUnitWidget.cs.meta new file mode 100644 index 0000000..f04edb4 --- /dev/null +++ b/Editor/Widgets/PinballEventUnitWidget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 37132c71449ce5846bc0c2b2937c4700 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Widgets/PulseCoilUnitWidget.cs b/Editor/Widgets/PulseCoilUnitWidget.cs index 7120ca0..c2adf73 100644 --- a/Editor/Widgets/PulseCoilUnitWidget.cs +++ b/Editor/Widgets/PulseCoilUnitWidget.cs @@ -24,33 +24,12 @@ namespace VisualPinball.Unity.VisualScripting.Editor { [Widget(typeof(PulseCoilUnit))] - public sealed class PulseCoilUnitWidget : GleUnitWidget + public sealed class PulseCoilUnitWidget : GleMultiUnitWidget { - private VariableNameInspector _coilIdInspector; - private readonly Func _setCoilInspectorConstructor; - public PulseCoilUnitWidget(FlowCanvas canvas, PulseCoilUnit unit) : base(canvas, unit) { - _setCoilInspectorConstructor = meta => new VariableNameInspector(meta, GetNameSuggestions); } - public override Inspector GetPortInspector(IUnitPort port, Metadata meta) - { - if (port == unit.Id) { - InspectorProvider.instance.Renew(ref _coilIdInspector, meta, _setCoilInspectorConstructor); - return _coilIdInspector; - } - - return base.GetPortInspector(port, meta); - } - - private IEnumerable GetNameSuggestions() - { - if (!GameObjectAvailable) { - return new List(); - } - var gle = Gle; - return gle == null ? new List() : gle.AvailableCoils.Select(coil => coil.Id).ToList(); - } + protected override IEnumerable IdSuggestions(IGamelogicEngine gle) => gle.RequestedCoils.Select(coil => coil.Id); } } diff --git a/Editor/Widgets/PulseSwitchUnitWidget.cs b/Editor/Widgets/PulseSwitchUnitWidget.cs new file mode 100644 index 0000000..985cc59 --- /dev/null +++ b/Editor/Widgets/PulseSwitchUnitWidget.cs @@ -0,0 +1,34 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using System.Collections.Generic; +using System.Linq; +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Widget(typeof(PulseSwitchUnit))] + public sealed class PulseSwitchUnitWidget : GleMultiUnitWidget + { + public PulseSwitchUnitWidget(FlowCanvas canvas, PulseSwitchUnit unit) : base(canvas, unit) + { + } + + protected override IEnumerable IdSuggestions(IGamelogicEngine gle) => gle.RequestedSwitches.Select(sw => sw.Id); + } +} diff --git a/Editor/Widgets/PulseSwitchUnitWidget.cs.meta b/Editor/Widgets/PulseSwitchUnitWidget.cs.meta new file mode 100644 index 0000000..129c454 --- /dev/null +++ b/Editor/Widgets/PulseSwitchUnitWidget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ee1bffdc400344c49bc77e8747ad2d23 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Widgets/SetCoilUnitWidget.cs b/Editor/Widgets/SetCoilUnitWidget.cs index 7c59c14..e8e3d1e 100644 --- a/Editor/Widgets/SetCoilUnitWidget.cs +++ b/Editor/Widgets/SetCoilUnitWidget.cs @@ -16,7 +16,6 @@ // ReSharper disable UnusedType.Global -using System; using System.Collections.Generic; using System.Linq; using Unity.VisualScripting; @@ -24,33 +23,12 @@ namespace VisualPinball.Unity.VisualScripting.Editor { [Widget(typeof(SetCoilUnit))] - public sealed class SetCoilUnitWidget : GleUnitWidget + public sealed class SetCoilUnitWidget : GleMultiUnitWidget { - private VariableNameInspector _coilIdInspector; - private readonly Func _setCoilInspectorConstructor; - public SetCoilUnitWidget(FlowCanvas canvas, SetCoilUnit unit) : base(canvas, unit) { - _setCoilInspectorConstructor = meta => new VariableNameInspector(meta, GetNameSuggestions); } - public override Inspector GetPortInspector(IUnitPort port, Metadata meta) - { - if (port == unit.Id) { - InspectorProvider.instance.Renew(ref _coilIdInspector, meta, _setCoilInspectorConstructor); - return _coilIdInspector; - } - - return base.GetPortInspector(port, meta); - } - - private IEnumerable GetNameSuggestions() - { - if (!GameObjectAvailable) { - return new List(); - } - var gle = Gle; - return gle == null ? new List() : gle.AvailableCoils.Select(coil => coil.Id).ToList(); - } + protected override IEnumerable IdSuggestions(IGamelogicEngine gle) => gle.RequestedCoils.Select(coil => coil.Id); } } diff --git a/Editor/Widgets/SetLampUnitWidget.cs b/Editor/Widgets/SetLampUnitWidget.cs index 32ab8c0..f93d404 100644 --- a/Editor/Widgets/SetLampUnitWidget.cs +++ b/Editor/Widgets/SetLampUnitWidget.cs @@ -16,7 +16,6 @@ // ReSharper disable UnusedType.Global -using System; using System.Collections.Generic; using System.Linq; using Unity.VisualScripting; @@ -24,33 +23,12 @@ namespace VisualPinball.Unity.VisualScripting.Editor { [Widget(typeof(SetLampUnit))] - public sealed class SetLampUnitWidget : GleUnitWidget + public sealed class SetLampUnitWidget : GleMultiUnitWidget { - private VariableNameInspector _lampIdInspector; - private readonly Func _setLampInspectorConstructor; - public SetLampUnitWidget(FlowCanvas canvas, SetLampUnit unit) : base(canvas, unit) { - _setLampInspectorConstructor = meta => new VariableNameInspector(meta, GetNameSuggestions); } - public override Inspector GetPortInspector(IUnitPort port, Metadata meta) - { - if (port == unit.Id) { - InspectorProvider.instance.Renew(ref _lampIdInspector, meta, _setLampInspectorConstructor); - return _lampIdInspector; - } - - return base.GetPortInspector(port, meta); - } - - private IEnumerable GetNameSuggestions() - { - if (!GameObjectAvailable) { - return new List(); - } - var gle = Gle; - return gle == null ? new List() : gle.AvailableLamps.Select(lamp => lamp.Id).ToList(); - } + protected override IEnumerable IdSuggestions(IGamelogicEngine gle) => gle.RequestedLamps.Select(lamp => lamp.Id); } } diff --git a/Editor/Widgets/SetSwitchUnitWidget.cs b/Editor/Widgets/SetSwitchUnitWidget.cs new file mode 100644 index 0000000..78e8829 --- /dev/null +++ b/Editor/Widgets/SetSwitchUnitWidget.cs @@ -0,0 +1,34 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using System.Collections.Generic; +using System.Linq; +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Widget(typeof(SetSwitchUnit))] + public sealed class SetSwitchUnitWidget : GleMultiUnitWidget + { + public SetSwitchUnitWidget(FlowCanvas canvas, SetSwitchUnit unit) : base(canvas, unit) + { + } + + protected override IEnumerable IdSuggestions(IGamelogicEngine gle) => gle.RequestedSwitches.Select(sw => sw.Id); + } +} diff --git a/Editor/Widgets/SetSwitchUnitWidget.cs.meta b/Editor/Widgets/SetSwitchUnitWidget.cs.meta new file mode 100644 index 0000000..d62d867 --- /dev/null +++ b/Editor/Widgets/SetSwitchUnitWidget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fabf8156812a34b91913deac9310e0dc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Widgets/SetVariableUnitWidget.cs b/Editor/Widgets/SetVariableUnitWidget.cs new file mode 100644 index 0000000..cf6609a --- /dev/null +++ b/Editor/Widgets/SetVariableUnitWidget.cs @@ -0,0 +1,38 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Widget(typeof(SetPlayerVariableUnit))] + public sealed class SetPlayerVariableUnitWidget : GleUnitWidget + { + public SetPlayerVariableUnitWidget(FlowCanvas canvas, SetPlayerVariableUnit unit) : base(canvas, unit) + { + } + } + + [Widget(typeof(SetTableVariableUnit))] + public sealed class SetTableVariableUnitWidget : GleUnitWidget + { + public SetTableVariableUnitWidget(FlowCanvas canvas, SetTableVariableUnit unit) : base(canvas, unit) + { + } + } +} diff --git a/Editor/Widgets/SetVariableUnitWidget.cs.meta b/Editor/Widgets/SetVariableUnitWidget.cs.meta new file mode 100644 index 0000000..fc7991b --- /dev/null +++ b/Editor/Widgets/SetVariableUnitWidget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6e8a3a02b5f6b414795248941a42d19a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Widgets/SwitchEnabledEventUnitWidget.cs b/Editor/Widgets/SwitchEnabledEventUnitWidget.cs new file mode 100644 index 0000000..2f73b24 --- /dev/null +++ b/Editor/Widgets/SwitchEnabledEventUnitWidget.cs @@ -0,0 +1,34 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using System.Collections.Generic; +using System.Linq; +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Widget(typeof(SwitchEnabledEventUnit))] + public sealed class SwitchEnabledEventUnitWidget : GleMultiUnitWidget + { + public SwitchEnabledEventUnitWidget(FlowCanvas canvas, SwitchEnabledEventUnit unit) : base(canvas, unit) + { + } + + protected override IEnumerable IdSuggestions(IGamelogicEngine gle) => gle.RequestedSwitches.Select(sw => sw.Id); + } +} diff --git a/Editor/Widgets/SwitchEnabledEventUnitWidget.cs.meta b/Editor/Widgets/SwitchEnabledEventUnitWidget.cs.meta new file mode 100644 index 0000000..a932460 --- /dev/null +++ b/Editor/Widgets/SwitchEnabledEventUnitWidget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d1a289dc9bb6e4020b64677e18de4f43 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Widgets/SwitchEventUnitWidget.cs b/Editor/Widgets/SwitchEventUnitWidget.cs index d4d98c4..6c59efd 100644 --- a/Editor/Widgets/SwitchEventUnitWidget.cs +++ b/Editor/Widgets/SwitchEventUnitWidget.cs @@ -16,7 +16,6 @@ // ReSharper disable UnusedType.Global -using System; using System.Collections.Generic; using System.Linq; using Unity.VisualScripting; @@ -24,34 +23,12 @@ namespace VisualPinball.Unity.VisualScripting.Editor { [Widget(typeof(SwitchEventUnit))] - public sealed class SwitchEventUnitWidget : GleUnitWidget + public sealed class SwitchEventUnitWidget : GleMultiUnitWidget { - private VariableNameInspector _lampIdInspector; - private readonly Func _switchIdInspectorConstructor; - public SwitchEventUnitWidget(FlowCanvas canvas, SwitchEventUnit unit) : base(canvas, unit) { - _switchIdInspectorConstructor = meta => new VariableNameInspector(meta, GetNameSuggestions); - } - - public override Inspector GetPortInspector(IUnitPort port, Metadata meta) - { - if (port == unit.Id) { - InspectorProvider.instance.Renew(ref _lampIdInspector, meta, _switchIdInspectorConstructor); - - return _lampIdInspector; - } - - return base.GetPortInspector(port, meta); } - private IEnumerable GetNameSuggestions() - { - if (!GameObjectAvailable) { - return new List(); - } - var gle = Gle; - return gle == null ? new List() : gle.AvailableSwitches.Select(lamp => lamp.Id).ToList(); - } + protected override IEnumerable IdSuggestions(IGamelogicEngine gle) => gle.RequestedSwitches.Select(sw => sw.Id); } } diff --git a/Editor/Widgets/SwitchLampUnitWidget.cs b/Editor/Widgets/SwitchLampUnitWidget.cs new file mode 100644 index 0000000..9ae0e1e --- /dev/null +++ b/Editor/Widgets/SwitchLampUnitWidget.cs @@ -0,0 +1,63 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using System; +using System.Collections.Generic; +using System.Linq; +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Widget(typeof(SwitchLampUnit))] + public sealed class SwitchLampUnitWidget : GleUnitWidget + { + private readonly List> _lampIdInspectorConstructorList; + + public SwitchLampUnitWidget(FlowCanvas canvas, SwitchLampUnit unit) : base(canvas, unit) + { + _lampIdInspectorConstructorList = new List>(); + } + + public override Inspector GetPortInspector(IUnitPort port, Metadata meta) + { + if (_lampIdInspectorConstructorList.Count() < unit.inputCount) { + for (var index = 0; index < unit.inputCount - _lampIdInspectorConstructorList.Count(); index++) { + _lampIdInspectorConstructorList.Add(meta => new LampIdValueInspector(meta, GetNameSuggestions)); + } + } + + for (var index = 0; index < unit.inputCount; index++) { + if (unit.multiInputs[index] == port) { + LampIdValueInspector lampIdInspector = new LampIdValueInspector(meta, GetNameSuggestions); + InspectorProvider.instance.Renew(ref lampIdInspector, meta, _lampIdInspectorConstructorList[index]); + + return lampIdInspector; + } + } + + return base.GetPortInspector(port, meta); + } + + private IEnumerable GetNameSuggestions() + { + return !GleAvailable + ? new List() + : Gle.RequestedLamps.Select(lamp => lamp.Id).ToList(); + } + } +} diff --git a/Editor/Widgets/SwitchLampUnitWidget.cs.meta b/Editor/Widgets/SwitchLampUnitWidget.cs.meta new file mode 100644 index 0000000..a3f8f09 --- /dev/null +++ b/Editor/Widgets/SwitchLampUnitWidget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eb81ebf5658344079b2463a97cc60251 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Widgets/TriggerPinballEventUnitWidget.cs b/Editor/Widgets/TriggerPinballEventUnitWidget.cs new file mode 100644 index 0000000..7345001 --- /dev/null +++ b/Editor/Widgets/TriggerPinballEventUnitWidget.cs @@ -0,0 +1,30 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Widget(typeof(TriggerPinballEventUnit))] + public sealed class TriggerPinballEventUnitWidget : GleUnitWidget + { + public TriggerPinballEventUnitWidget(FlowCanvas canvas, TriggerPinballEventUnit unit) : base(canvas, unit) + { + } + } +} diff --git a/Editor/Widgets/TriggerPinballEventUnitWidget.cs.meta b/Editor/Widgets/TriggerPinballEventUnitWidget.cs.meta new file mode 100644 index 0000000..4175209 --- /dev/null +++ b/Editor/Widgets/TriggerPinballEventUnitWidget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bcc0505d85dfff748885fc1f0087c178 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Widgets/UpdateDisplayUnitWidget.cs b/Editor/Widgets/UpdateDisplayUnitWidget.cs new file mode 100644 index 0000000..6c58163 --- /dev/null +++ b/Editor/Widgets/UpdateDisplayUnitWidget.cs @@ -0,0 +1,30 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Widget(typeof(UpdateDisplayUnit))] + public sealed class UpdateDisplayUnitWidget : GleUnitWidget + { + public UpdateDisplayUnitWidget(FlowCanvas canvas, UpdateDisplayUnit unit) : base(canvas, unit) + { + } + } +} diff --git a/Editor/Widgets/UpdateDisplayUnitWidget.cs.meta b/Editor/Widgets/UpdateDisplayUnitWidget.cs.meta new file mode 100644 index 0000000..f7e2da1 --- /dev/null +++ b/Editor/Widgets/UpdateDisplayUnitWidget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d01edfa85b5aaa440a46ba9425b8ea0e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Widgets/VariableChangedEventUnitWidget.cs b/Editor/Widgets/VariableChangedEventUnitWidget.cs new file mode 100644 index 0000000..cec0141 --- /dev/null +++ b/Editor/Widgets/VariableChangedEventUnitWidget.cs @@ -0,0 +1,38 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable UnusedType.Global + +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting.Editor +{ + [Widget(typeof(PlayerVariableChangedEventUnit))] + public sealed class PlayerVariableChangedEventWidget : GleUnitWidget + { + public PlayerVariableChangedEventWidget(FlowCanvas canvas, PlayerVariableChangedEventUnit unit) : base(canvas, unit) + { + } + } + + [Widget(typeof(TableVariableChangedEventUnit))] + public sealed class TableVariableChangedEventWidget : GleUnitWidget + { + public TableVariableChangedEventWidget(FlowCanvas canvas, TableVariableChangedEventUnit unit) : base(canvas, unit) + { + } + } +} diff --git a/Editor/Widgets/VariableChangedEventUnitWidget.cs.meta b/Editor/Widgets/VariableChangedEventUnitWidget.cs.meta new file mode 100644 index 0000000..8e1395d --- /dev/null +++ b/Editor/Widgets/VariableChangedEventUnitWidget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2c3fcf5eb49511d4b980d230d859c903 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Display.meta b/Runtime/Display.meta new file mode 100644 index 0000000..a15249f --- /dev/null +++ b/Runtime/Display.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1e0c1c31f7904ee7b6a97fae6157da9f +timeCreated: 1644188526 \ No newline at end of file diff --git a/Runtime/Display/DisplayDefinition.cs b/Runtime/Display/DisplayDefinition.cs new file mode 100644 index 0000000..6fc5cce --- /dev/null +++ b/Runtime/Display/DisplayDefinition.cs @@ -0,0 +1,42 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable InconsistentNaming + +using System; +using System.Collections.Generic; + +namespace VisualPinball.Unity.VisualScripting +{ + [Serializable] + public class DisplayDefinition + { + public string Id = "display0"; + public int Width = 128; + public int Height = 32; + + public DisplayFrameFormat[] SupportedFormats = { + DisplayFrameFormat.AlphaNumeric + }; + + public bool Supports(DisplayFrameFormat format) + { + return SupportedFormats != null && Array.IndexOf(SupportedFormats, format) >= 0; + } + + public DisplayConfig DisplayConfig => new(Id, Width, Height); + } +} diff --git a/Runtime/Display/DisplayDefinition.cs.meta b/Runtime/Display/DisplayDefinition.cs.meta new file mode 100644 index 0000000..14f6b74 --- /dev/null +++ b/Runtime/Display/DisplayDefinition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e7318cd2d8e566247adaaa3ea00572dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Gamelogic/EventDefinition.cs b/Runtime/Gamelogic/EventDefinition.cs new file mode 100644 index 0000000..fc3cb17 --- /dev/null +++ b/Runtime/Gamelogic/EventDefinition.cs @@ -0,0 +1,32 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable InconsistentNaming + +using System; + +namespace VisualPinball.Unity.VisualScripting +{ + [Serializable] + public class EventDefinition + { + public string Name; + public string Id; + + public bool HasId => !string.IsNullOrEmpty(Id); + public void GenerateId() => Id = Guid.NewGuid().ToString()[..13]; + } +} diff --git a/Runtime/Gamelogic/EventDefinition.cs.meta b/Runtime/Gamelogic/EventDefinition.cs.meta new file mode 100644 index 0000000..4cc854d --- /dev/null +++ b/Runtime/Gamelogic/EventDefinition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 035b10e41eafa234285fd151c7640158 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Gamelogic/State.cs b/Runtime/Gamelogic/State.cs new file mode 100644 index 0000000..3663421 --- /dev/null +++ b/Runtime/Gamelogic/State.cs @@ -0,0 +1,170 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.Collections.Generic; +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting +{ + [Serializable] + public class PlayerState : State + { + public readonly int Id; + + public PlayerState(int id) + { + Id = id; + } + protected override string VariableChangedEventName => VisualScriptingEventNames.PlayerVariableChanged; + } + + [Serializable] + public class TableState : State + { + protected override string VariableChangedEventName => VisualScriptingEventNames.TableVariableChanged; + } + + public abstract class State + { + protected abstract string VariableChangedEventName { get; } + + private readonly Dictionary _variables = new(); + + public void AddProperty(StateVariable variable) + { + _variables[variable.Id] = variable; + } + + public T Get(string variableId) where T : class + { + if (!_variables.ContainsKey(variableId)) { + throw new ArgumentException($"No such variable ID ({variableId}).", nameof(variableId)); + } + if (_variables[variableId].Type != typeof(T)) { + throw new InvalidOperationException($"Variable \"{variableId}\" is of type {_variables[variableId].Type}, but you asked for a {typeof(T)}."); + } + + return _variables[variableId].Get(); + } + + public StateVariable GetVariable(string variableId) => _variables[variableId]; + + public object Get(string variableId) + { + if (!_variables.ContainsKey(variableId)) { + throw new ArgumentException($"No such variable ID ({variableId}).", nameof(variableId)); + } + + if (_variables[variableId].Type == typeof(string)) { + return Get(variableId); + } + if (_variables[variableId].Type == typeof(Integer)) { + return Get(variableId); + } + if (_variables[variableId].Type == typeof(Float)) { + return Get(variableId); + } + if (_variables[variableId].Type == typeof(Bool)) { + return Get(variableId); + } + + throw new InvalidOperationException($"Unknown type of variable {_variables[variableId].Name}."); + } + + public void Set(string variableId, T value) where T : class + { + if (!_variables.ContainsKey(variableId)) { + throw new ArgumentException($"No such variable ID ({variableId}).", nameof(variableId)); + } + if (_variables[variableId].Type != value.GetType()) { + throw new ArgumentException($"Variable \"{variableId}\" is of type {_variables[variableId].Type}, but you provided a {value.GetType()}.", nameof(value)); + } + + var currentValue = _variables[variableId].Get(); + _variables[variableId].Set(value); + + if (currentValue != value) { + EventBus.Trigger( + VariableChangedEventName, + new VariableChangedArgs(variableId, currentValue, value) + ); + } + } + } + + [Serializable] + public class Integer + { + private readonly int _value; + public Integer(int value) + { + _value = value; + } + public static Integer operator +(Integer lhs, Integer rhs) => new(lhs._value + rhs._value); + public static Integer operator -(Integer lhs, Integer rhs) => new(lhs._value - rhs._value); + public static Integer operator *(Integer lhs, Integer rhs) => new(lhs._value * rhs._value); + public static Integer operator /(Integer lhs, Integer rhs) => new(lhs._value / rhs._value); + public static implicit operator int(Integer num) => num._value; + public static implicit operator Integer(int num) => new(num); + public override string ToString() => _value.ToString(); + } + + [Serializable] + public class Float + { + private readonly float _value; + public Float(float value) + { + _value = value; + } + public static Float operator +(Float lhs, Float rhs) => new(lhs._value + rhs._value); + public static Float operator -(Float lhs, Float rhs) => new(lhs._value - rhs._value); + public static Float operator *(Float lhs, Float rhs) => new(lhs._value * rhs._value); + public static Float operator /(Float lhs, Float rhs) => new(lhs._value / rhs._value); + public static implicit operator float(Float num) => num._value; + public static implicit operator Float(float num) => new(num); + public override string ToString() => _value.ToString(); + } + + [Serializable] + public class Bool + { + private readonly bool _value; + public Bool(bool value) + { + _value = value; + } + public static implicit operator bool(Bool num) => num._value; + public static implicit operator Bool(bool num) => new(num); + public override string ToString() => _value.ToString(); + } + + public readonly struct VariableChangedArgs + { + public readonly string VariableId; + + public readonly object OldValue; + public readonly object NewValue; + + public VariableChangedArgs(string variableId, object oldValue, object newValue) + { + VariableId = variableId; + OldValue = oldValue; + NewValue = newValue; + } + } +} diff --git a/Runtime/Gamelogic/State.cs.meta b/Runtime/Gamelogic/State.cs.meta new file mode 100644 index 0000000..ad6cf01 --- /dev/null +++ b/Runtime/Gamelogic/State.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6eb6c1f2a9e08ee429d86cefd79d92dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Gamelogic/StateVariable.cs b/Runtime/Gamelogic/StateVariable.cs new file mode 100644 index 0000000..06b1433 --- /dev/null +++ b/Runtime/Gamelogic/StateVariable.cs @@ -0,0 +1,104 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; + +namespace VisualPinball.Unity.VisualScripting +{ + public class StateVariable : IEquatable + { + public string Id; + public string Name; + public Type Type; // always *object* type (string, Integer, Float, Bool) + private object _value; + + public StateVariable(string id, string name, string initialValue) : this(id, name, typeof(string), initialValue) + { + } + public StateVariable(string id, string name, int initialValue) : this(id, name, typeof(Integer),new Integer(initialValue)) + { + } + public StateVariable(string id, string name, float initialValue) : this(id, name, typeof(Float), new Float(initialValue)) + { + } + public StateVariable(string id, string name, bool initialValue) : this(id, name, typeof(Bool), new Bool(initialValue)) + { + } + + private StateVariable(string id, string name, Type type, object initialValue) + { + Id = id; + Name = name; + Type = type; + _value = initialValue; + } + + public T Get() where T : class + { + return _value as T; + } + + public void Set(T value) + { + _value = value; + } + + public bool Equals(StateVariable other) + { + if (ReferenceEquals(null, other)) { + return false; + } + if (ReferenceEquals(this, other)) { + return true; + } + + if (other.Type != Type) { + return false; + } + + if (Type == typeof(string)) { + return string.Equals(_value as string, other._value as string); + } + if (Type == typeof(int)) { + return (int)_value == (int)other._value; + } + if (Type == typeof(float)) { + return (float)_value == (float)other._value; + } + if (Type == typeof(bool)) { + return (bool)_value == (bool)other._value; + } + return false; + } + + public override bool Equals(object obj) => Equals(obj as StateVariable); + + public override int GetHashCode() + { + return (Id, Name, Type, _value).GetHashCode(); + } + + public static bool operator ==(StateVariable lhs, StateVariable rhs) + { + if (lhs is null) { + return rhs is null; + } + return lhs.Equals(rhs); + } + + public static bool operator !=(StateVariable lhs, StateVariable rhs) => !(lhs == rhs); + } +} diff --git a/Runtime/Gamelogic/StateVariable.cs.meta b/Runtime/Gamelogic/StateVariable.cs.meta new file mode 100644 index 0000000..964aafb --- /dev/null +++ b/Runtime/Gamelogic/StateVariable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b1a9c954a9a68a14ea503f77975b743a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Gamelogic/VariableDefinition.cs b/Runtime/Gamelogic/VariableDefinition.cs new file mode 100644 index 0000000..4adcefa --- /dev/null +++ b/Runtime/Gamelogic/VariableDefinition.cs @@ -0,0 +1,68 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable InconsistentNaming + +using System; + +namespace VisualPinball.Unity.VisualScripting +{ + [Serializable] + public class PlayerVariableDefinition : VariableDefinition + { + } + + [Serializable] + public class TableVariableDefinition : VariableDefinition + { + } + + public abstract class VariableDefinition + { + public string Id; + public string Name; + public VariableType Type; + + public string StringDefaultValue; + public int IntegerDefaultValue; + public float FloatDefaultValue; + public bool BooleanDefaultValue; + + public StateVariable Instantiate() + { + switch (Type) { + case VariableType.String: + return new StateVariable(Id, Name, StringDefaultValue); + case VariableType.Integer: + return new StateVariable(Id, Name, IntegerDefaultValue); + case VariableType.Float: + return new StateVariable(Id, Name, FloatDefaultValue); + case VariableType.Boolean: + return new StateVariable(Id, Name, BooleanDefaultValue); + default: + throw new ArgumentOutOfRangeException(); + } + } + + public bool HasId => !string.IsNullOrEmpty(Id); + public void GenerateId() => Id = Guid.NewGuid().ToString()[..13]; + } + + public enum VariableType + { + String, Integer, Float, Boolean + } +} diff --git a/Runtime/Gamelogic/VariableDefinition.cs.meta b/Runtime/Gamelogic/VariableDefinition.cs.meta new file mode 100644 index 0000000..617b879 --- /dev/null +++ b/Runtime/Gamelogic/VariableDefinition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6630e10b701f88d4ebfbfc4e45efc52d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Gamelogic/VisualScriptingEventNames.cs b/Runtime/Gamelogic/VisualScriptingEventNames.cs index 8805ddd..461b07f 100644 --- a/Runtime/Gamelogic/VisualScriptingEventNames.cs +++ b/Runtime/Gamelogic/VisualScriptingEventNames.cs @@ -22,5 +22,9 @@ public static class VisualScriptingEventNames public const string LampEvent = "LampEvent"; public const string SwitchEvent = "SwitchEvent"; public const string CoilEvent = "CoilEvent"; + public const string CurrentPlayerChanged = "CurrentPlayerChanged"; + public const string PlayerVariableChanged = "PlayerVariableChanged"; + public const string TableVariableChanged = "TableVariableChanged"; + public const string PinballEvent = "PinballEvent"; } } diff --git a/Runtime/Gamelogic/VisualScriptingGamelogicBridge.cs b/Runtime/Gamelogic/VisualScriptingGamelogicBridge.cs index 3add681..41f4ebd 100644 --- a/Runtime/Gamelogic/VisualScriptingGamelogicBridge.cs +++ b/Runtime/Gamelogic/VisualScriptingGamelogicBridge.cs @@ -76,7 +76,9 @@ private void OnStarted(object sender, EventArgs e) private static void OnSwitchChanged(object sender, SwitchEventArgs2 e) { - EventBus.Trigger(VisualScriptingEventNames.SwitchEvent, new SwitchEventArgs2(e.Id, e.IsEnabled)); + var args = new SwitchEventArgs2(e.Id, e.IsEnabled); + + EventBus.Trigger(VisualScriptingEventNames.SwitchEvent, args); } private static void OnCoilChanged(object sender, CoilEventArgs e) diff --git a/Runtime/Gamelogic/VisualScriptingGamelogicEngine.cs b/Runtime/Gamelogic/VisualScriptingGamelogicEngine.cs index 8403214..de60734 100644 --- a/Runtime/Gamelogic/VisualScriptingGamelogicEngine.cs +++ b/Runtime/Gamelogic/VisualScriptingGamelogicEngine.cs @@ -17,6 +17,7 @@ // ReSharper disable InconsistentNaming using System; +using System.Collections.Generic; using System.Linq; using Unity.VisualScripting; using UnityEngine; @@ -26,29 +27,46 @@ namespace VisualPinball.Unity.VisualScripting { [DisallowMultipleComponent] [AddComponentMenu("Visual Pinball/Gamelogic Engine/Visual Scripting Game Logic")] - public class VisualScriptingGamelogicEngine : MonoBehaviour, IGamelogicEngine + public class VisualScriptingGamelogicEngine : MonoBehaviour, IGamelogicEngine, ISerializationCallbackReceiver { public string Name => "Visual Scripting Gamelogic Engine"; + [Tooltip("Define here the global variables of the Visual Scripting engine.")] + public List TableVariableDefinitions; + + [Tooltip("Define here the player-specific variables of the Visual Scripting engine.")] + public List PlayerVariableDefinitions; + + [Tooltip("Declare your custom events here for easy access with our event nodes.")] + public List EventDefinitions; + + [Tooltip("Define the displays this game is going to use.")] + public DisplayDefinition[] Displays; + [Tooltip("The switches that are exposed in the Visual Scripting nodes.")] public VisualScriptingSwitch[] Switches; + + [Tooltip("The coils that are exposed in the Visual Scripting nodes.")] public VisualScriptingCoil[] Coils; + + [Tooltip("The lamps that are exposed in the Visual Scripting nodes.")] public VisualScriptingLamp[] Lamps; public GamelogicEngineWire[] Wires; - public GamelogicEngineSwitch[] AvailableSwitches => Switches.Select(sw => sw as GamelogicEngineSwitch).ToArray(); + public DisplayConfig[] RequiredDisplays => Displays.Select(d => d.DisplayConfig).ToArray(); + + public GamelogicEngineSwitch[] RequestedSwitches => Switches.Select(sw => sw as GamelogicEngineSwitch).ToArray(); - public GamelogicEngineLamp[] AvailableLamps => Lamps.Select(lamp => lamp as GamelogicEngineLamp).ToArray(); + public GamelogicEngineLamp[] RequestedLamps => Lamps.Select(lamp => lamp as GamelogicEngineLamp).ToArray(); - public GamelogicEngineCoil[] AvailableCoils => Coils.Select(c => c as GamelogicEngineCoil).ToArray(); + public GamelogicEngineCoil[] RequestedCoils => Coils.Select(c => c as GamelogicEngineCoil).ToArray(); public GamelogicEngineWire[] AvailableWires => Wires; - public event EventHandler OnDisplaysAvailable; + public event EventHandler OnDisplaysRequested; public event EventHandler OnDisplayFrame; public event EventHandler OnLampChanged; public event EventHandler OnLampsChanged; - public event EventHandler OnLampColorChanged; public event EventHandler OnCoilChanged; public event EventHandler OnSwitchChanged; public event EventHandler OnStarted; @@ -56,18 +74,98 @@ public class VisualScriptingGamelogicEngine : MonoBehaviour, IGamelogicEngine [NonSerialized] public BallManager BallManager; [NonSerialized] private Player _player; + [NonSerialized] private int _currentPlayer; + [NonSerialized] public readonly TableState TableState = new (); + [NonSerialized] public readonly Dictionary PlayerStates = new (); + + public PlayerState CurrentPlayerState { + get { + if (!PlayerStates.ContainsKey(_currentPlayer)) { + throw new InvalidOperationException("Must create a player state before accessing it!"); + } + return PlayerStates[_currentPlayer]; + } + } + + public void DisplayFrame(DisplayFrameData data) + { + OnDisplayFrame?.Invoke(this, data); + } + + public void SetCurrentPlayer(int value, bool forceNotify = false) + { + if (!PlayerStates.ContainsKey(value)) { + Debug.LogError($"Cannot change to non-existing player {value}."); + return; + } + var previousPlayer = _currentPlayer; + _currentPlayer = value; + if (forceNotify || previousPlayer != _currentPlayer) { + EventBus.Trigger(VisualScriptingEventNames.CurrentPlayerChanged, EventArgs.Empty); + } + + // also trigger updates for each variable + foreach (var varDef in PlayerVariableDefinitions) { + var before = PlayerStates[previousPlayer].GetVariable(varDef.Id); + var now = PlayerStates[_currentPlayer].GetVariable(varDef.Id); + if (PlayerStates.ContainsKey(previousPlayer)) { + if (forceNotify || before != now) { + EventBus.Trigger(VisualScriptingEventNames.PlayerVariableChanged, new VariableChangedArgs(varDef.Id, before.Get(), now.Get())); + } + + } else { + EventBus.Trigger(VisualScriptingEventNames.PlayerVariableChanged, new VariableChangedArgs(varDef.Id, before.Get(), now.Get())); + } + } + } + + public void CreatePlayerState(int playerId) + { + if (PlayerStates.ContainsKey(playerId)) { + Debug.LogWarning($"Tried to create new player state for existing state {playerId}, skipping."); + return; + } + var playerState = new PlayerState(playerId); + foreach (var propertyDefinition in PlayerVariableDefinitions) { + playerState.AddProperty(propertyDefinition.Instantiate()); + } + PlayerStates[playerId] = playerState; + + // switch to this state if current state is invalid + if (!PlayerStates.ContainsKey(_currentPlayer)) { + SetCurrentPlayer(playerId, true); + } + } + + public void DestroyPlayerStates() + { + PlayerStates.Clear(); + _currentPlayer = 0; + } + public void OnInit(Player player, TableApi tableApi, BallManager ballManager) { _player = player; BallManager = ballManager; + // request displays + OnDisplaysRequested?.Invoke(this, new RequestedDisplays(Displays.Select(d => d.DisplayConfig).ToArray())); + + // create table variables + foreach (var propertyDefinition in TableVariableDefinitions) { + TableState.AddProperty(propertyDefinition.Instantiate()); + } + OnStarted?.Invoke(this, EventArgs.Empty); EventBus.Trigger(VisualScriptingEventNames.GleStartedEvent, EventArgs.Empty); } public void Switch(string id, bool isClosed) { - OnSwitchChanged?.Invoke(this, new SwitchEventArgs2(id, isClosed)); - EventBus.Trigger(VisualScriptingEventNames.SwitchEvent, new SwitchEventArgs2(id, isClosed)); + var args = new SwitchEventArgs2(id, isClosed); + + OnSwitchChanged?.Invoke(this, args); + + EventBus.Trigger(VisualScriptingEventNames.SwitchEvent, args); } public void SetCoil(string id, bool isEnabled) @@ -80,14 +178,9 @@ public void SetLamp(string id, float value, bool isCoil = false, LampSource sour OnLampChanged?.Invoke(this, new LampEventArgs(id, value, isCoil, source)); } - public void SetLamp(string id, Color color) + public LampState GetLamp(string id) { - OnLampColorChanged?.Invoke(this, new LampColorEventArgs(id, color)); - } - - public float GetLamp(string id) - { - return _player.LampStatuses.ContainsKey(id) ? _player.LampStatuses[id] : 0; + return _player.LampStatuses.ContainsKey(id) ? _player.LampStatuses[id] : LampState.Default; } public bool GetSwitch(string id) @@ -99,5 +192,40 @@ public bool GetCoil(string id) { return _player.CoilStatuses.ContainsKey(id) && _player.CoilStatuses[id]; } + + + public void OnBeforeSerialize() + { + #if UNITY_EDITOR + + var ids = new HashSet(); + foreach (var def in PlayerVariableDefinitions) { + if (!def.HasId || ids.Contains(def.Id)) { + def.GenerateId(); + } + ids.Add(def.Id); + } + + ids.Clear(); + foreach (var def in TableVariableDefinitions) { + if (!def.HasId || ids.Contains(def.Id)) { + def.GenerateId(); + } + ids.Add(def.Id); + } + + ids.Clear(); + foreach (var def in EventDefinitions) { + if (!def.HasId || ids.Contains(def.Id)) { + def.GenerateId(); + } + ids.Add(def.Id); + } + #endif + } + public void OnAfterDeserialize() + { + } } } + diff --git a/Runtime/Nodes/Coils/AllCoilsEnabledEventUnit.cs b/Runtime/Nodes/Coils/AllCoilsEnabledEventUnit.cs new file mode 100644 index 0000000..0d083d1 --- /dev/null +++ b/Runtime/Nodes/Coils/AllCoilsEnabledEventUnit.cs @@ -0,0 +1,81 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Unity.VisualScripting; +using UnityEngine; + +namespace VisualPinball.Unity.VisualScripting +{ + [UnitTitle("On All Coils Enabled")] + [UnitSurtitle("Gamelogic Engine")] + [UnitCategory("Events\\Visual Pinball")] + public class AllCoilsEnabledEventUnit : GleEventUnit, IMultiInputUnit + { + [SerializeAs(nameof(inputCount))] + private int _inputCount = 1; + + [DoNotSerialize] + [Inspectable, UnitHeaderInspectable("Coil IDs")] + public int inputCount + { + get => _inputCount; + set => _inputCount = Mathf.Clamp(value, 1, 10); + } + + [DoNotSerialize] + public ReadOnlyCollection multiInputs { get; private set; } + + [DoNotSerialize] + protected override bool register => true; + + public override EventHook GetHook(GraphReference reference) => new EventHook(VisualScriptingEventNames.CoilEvent); + + protected override void Definition() + { + base.Definition(); + + var _multiInputs = new List(); + + multiInputs = _multiInputs.AsReadOnly(); + + for (var i = 0; i < inputCount; i++) { + _multiInputs.Add(ValueInput(i.ToString(), string.Empty)); + } + } + + protected override bool ShouldTrigger(Flow flow, CoilEventArgs args) + { + if (!AssertGle(flow)) { + Debug.LogError("Cannot find GLE."); + return false; + } + + var validCoil = false; + foreach(var input in multiInputs) { + var coilId = flow.GetValue(input); + if (coilId == args.Id) { + validCoil = true; + } + if (!Gle.GetCoil(coilId)) { + return false; + } + } + return validCoil; + } + } +} diff --git a/Runtime/Nodes/Coils/AllCoilsEnabledEventUnit.cs.meta b/Runtime/Nodes/Coils/AllCoilsEnabledEventUnit.cs.meta new file mode 100644 index 0000000..fa6ab1a --- /dev/null +++ b/Runtime/Nodes/Coils/AllCoilsEnabledEventUnit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9ccc99a11751b4d1b949c5e916689974 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/Coils/CoilEnabledEventUnit.cs b/Runtime/Nodes/Coils/CoilEnabledEventUnit.cs new file mode 100644 index 0000000..e64fee0 --- /dev/null +++ b/Runtime/Nodes/Coils/CoilEnabledEventUnit.cs @@ -0,0 +1,73 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Unity.VisualScripting; +using UnityEngine; + +namespace VisualPinball.Unity.VisualScripting +{ + [UnitTitle("On Coil Enabled")] + [UnitSurtitle("Gamelogic Engine")] + [UnitCategory("Events\\Visual Pinball")] + public class CoilEnabledEventUnit : GleEventUnit, IMultiInputUnit + { + [SerializeAs(nameof(inputCount))] + private int _inputCount = 1; + + [DoNotSerialize] + [Inspectable, UnitHeaderInspectable("Coil IDs")] + public int inputCount + { + get => _inputCount; + set => _inputCount = Mathf.Clamp(value, 1, 10); + } + + [DoNotSerialize] + public ReadOnlyCollection multiInputs { get; private set; } + + [DoNotSerialize] + protected override bool register => true; + + // Adding an EventHook with the name of the event to the list of visual scripting events. + public override EventHook GetHook(GraphReference reference) => new EventHook(VisualScriptingEventNames.CoilEvent); + + protected override void Definition() + { + base.Definition(); + + var _multiInputs = new List(); + + multiInputs = _multiInputs.AsReadOnly(); + + for (var i = 0; i < inputCount; i++) { + _multiInputs.Add(ValueInput(i.ToString(), string.Empty)); + } + } + + protected override bool ShouldTrigger(Flow flow, CoilEventArgs args) + { + foreach(var input in multiInputs) { + if (flow.GetValue(input) == args.Id && args.IsEnabled) { + return true; + } + } + + return false; + } + } +} diff --git a/Runtime/Nodes/Coils/CoilEnabledEventUnit.cs.meta b/Runtime/Nodes/Coils/CoilEnabledEventUnit.cs.meta new file mode 100644 index 0000000..375a126 --- /dev/null +++ b/Runtime/Nodes/Coils/CoilEnabledEventUnit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 36a430294a936419187f5dd803769fbf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/Coils/CoilEventUnit.cs b/Runtime/Nodes/Coils/CoilEventUnit.cs new file mode 100644 index 0000000..fb1361f --- /dev/null +++ b/Runtime/Nodes/Coils/CoilEventUnit.cs @@ -0,0 +1,86 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Unity.VisualScripting; +using UnityEngine; + +namespace VisualPinball.Unity.VisualScripting +{ + [UnitTitle("On Coil Changed")] + [UnitSurtitle("Gamelogic Engine")] + [UnitCategory("Events\\Visual Pinball")] + public class CoilEventUnit : GleEventUnit, IMultiInputUnit + { + [SerializeAs(nameof(inputCount))] + private int _inputCount = 1; + + [DoNotSerialize] + [Inspectable, UnitHeaderInspectable("Coil IDs")] + public int inputCount + { + get => _inputCount; + set => _inputCount = Mathf.Clamp(value, 1, 10); + } + + [DoNotSerialize] + public ReadOnlyCollection multiInputs { get; private set; } + + [DoNotSerialize] + [PortLabel("Is Enabled")] + public ValueOutput IsEnabled { get; private set; } + + protected override bool register => true; + + // Adding an EventHook with the name of the event to the list of visual scripting events. + public override EventHook GetHook(GraphReference reference) + { + return new EventHook(VisualScriptingEventNames.CoilEvent); + } + + protected override void Definition() + { + base.Definition(); + + var _multiInputs = new List(); + + multiInputs = _multiInputs.AsReadOnly(); + + for (var i = 0; i < inputCount; i++) { + _multiInputs.Add(ValueInput(i.ToString(), string.Empty)); + } + + IsEnabled = ValueOutput(nameof(IsEnabled)); + } + + protected override bool ShouldTrigger(Flow flow, CoilEventArgs args) + { + foreach (var input in multiInputs) { + if (flow.GetValue(input) == args.Id) { + return true; + } + } + + return false; + } + + protected override void AssignArguments(Flow flow, CoilEventArgs args) + { + flow.SetValue(IsEnabled, args.IsEnabled); + } + } +} diff --git a/Runtime/Nodes/Coils/CoilEventUnit.cs.meta b/Runtime/Nodes/Coils/CoilEventUnit.cs.meta new file mode 100644 index 0000000..1f6c98c --- /dev/null +++ b/Runtime/Nodes/Coils/CoilEventUnit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1741df536aa73483da12f445f839ccc4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/Coils/GetCoilUnit.cs b/Runtime/Nodes/Coils/GetCoilUnit.cs new file mode 100644 index 0000000..5dd27b7 --- /dev/null +++ b/Runtime/Nodes/Coils/GetCoilUnit.cs @@ -0,0 +1,51 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using Unity.VisualScripting; +using UnityEngine; + +namespace VisualPinball.Unity.VisualScripting +{ + [UnitTitle("Get Coil Value")] + [UnitSurtitle("Gamelogic Engine")] + [UnitCategory("Visual Pinball")] + public class GetCoilUnit : GleUnit + { + [DoNotSerialize] + [PortLabel("Coil ID")] + public ValueInput Id { get; private set; } + + [DoNotSerialize] + [PortLabel("Is Enabled")] + public ValueOutput IsEnabled { get; private set; } + + protected override void Definition() + { + Id = ValueInput(nameof(Id), string.Empty); + IsEnabled = ValueOutput(nameof(IsEnabled), GetEnabled); + } + + private bool GetEnabled(Flow flow) + { + if (!AssertGle(flow)) { + Debug.LogError("Cannot find GLE."); + return false; + } + + return Gle.GetCoil(flow.GetValue(Id)); + } + } +} diff --git a/Runtime/Nodes/Coils/GetCoilUnit.cs.meta b/Runtime/Nodes/Coils/GetCoilUnit.cs.meta new file mode 100644 index 0000000..7752012 --- /dev/null +++ b/Runtime/Nodes/Coils/GetCoilUnit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0b17b98dde58b4401a778eb1a28dbfce +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/Coils/PulseCoilUnit.cs b/Runtime/Nodes/Coils/PulseCoilUnit.cs index 137ac17..260ef8f 100644 --- a/Runtime/Nodes/Coils/PulseCoilUnit.cs +++ b/Runtime/Nodes/Coils/PulseCoilUnit.cs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +using System.Collections.Generic; +using System.Collections.ObjectModel; using Unity.VisualScripting; using UnityEngine; @@ -22,7 +24,7 @@ namespace VisualPinball.Unity.VisualScripting [UnitTitle("Pulse Coil")] [UnitSurtitle("Gamelogic Engine")] [UnitCategory("Visual Pinball")] - public class PulseCoilUnit : GleUnit + public class PulseCoilUnit : GleUnit, IMultiInputUnit { [DoNotSerialize] [PortLabelHidden] @@ -32,9 +34,19 @@ public class PulseCoilUnit : GleUnit [PortLabelHidden] public ControlOutput OutputTrigger; + [SerializeAs(nameof(inputCount))] + private int _inputCount = 1; + + [DoNotSerialize] + [Inspectable, UnitHeaderInspectable("Coil IDs")] + public int inputCount + { + get => _inputCount; + set => _inputCount = Mathf.Clamp(value, 1, 10); + } + [DoNotSerialize] - [PortLabel("Coil ID")] - public ValueInput Id { get; private set; } + public ReadOnlyCollection multiInputs { get; private set; } [DoNotSerialize] [PortLabel("Duration (ms)")] @@ -45,10 +57,19 @@ protected override void Definition() InputTrigger = ControlInput(nameof(InputTrigger), Process); OutputTrigger = ControlOutput(nameof(OutputTrigger)); - Id = ValueInput(nameof(Id), string.Empty); - PulseDuration = ValueInput(nameof(PulseDuration), 80); + var _multiInputs = new List(); + + multiInputs = _multiInputs.AsReadOnly(); + + for (var i = 0; i < inputCount; i++) { + var input = ValueInput(i.ToString(), string.Empty); + _multiInputs.Add(input); + + Requirement(input, InputTrigger); + } + + PulseDuration = ValueInput(nameof(PulseDuration), 80); - Requirement(Id, InputTrigger); Succession(InputTrigger, OutputTrigger); } @@ -60,15 +81,17 @@ private ControlOutput Process(Flow flow) } if (!AssertPlayer(flow)) { - Debug.LogError("Cannot find GLE."); + Debug.LogError("Cannot find Player."); return OutputTrigger; } - var id = flow.GetValue(Id); var pulseDuration = flow.GetValue(PulseDuration); - Gle.SetCoil(id, true); - Player.ScheduleAction(pulseDuration, () => Gle.SetCoil(id, false)); + foreach (var input in multiInputs) { + var coilId = flow.GetValue(input); + Gle.SetCoil(coilId, true); + Player.ScheduleAction(pulseDuration, () => Gle.SetCoil(coilId, false)); + } return OutputTrigger; } diff --git a/Runtime/Nodes/Coils/SetCoilUnit.cs b/Runtime/Nodes/Coils/SetCoilUnit.cs index 69eee0b..ae37fcc 100644 --- a/Runtime/Nodes/Coils/SetCoilUnit.cs +++ b/Runtime/Nodes/Coils/SetCoilUnit.cs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +using System.Collections.Generic; +using System.Collections.ObjectModel; using Unity.VisualScripting; using UnityEngine; @@ -22,7 +24,7 @@ namespace VisualPinball.Unity.VisualScripting [UnitTitle("Set Coil")] [UnitSurtitle("Gamelogic Engine")] [UnitCategory("Visual Pinball")] - public class SetCoilUnit : GleUnit + public class SetCoilUnit : GleUnit, IMultiInputUnit { [DoNotSerialize] [PortLabelHidden] @@ -32,9 +34,19 @@ public class SetCoilUnit : GleUnit [PortLabelHidden] public ControlOutput OutputTrigger; + [SerializeAs(nameof(inputCount))] + private int _inputCount = 1; + + [DoNotSerialize] + [Inspectable, UnitHeaderInspectable("Coil IDs")] + public int inputCount + { + get => _inputCount; + set => _inputCount = Mathf.Clamp(value, 1, 10); + } + [DoNotSerialize] - [PortLabel("Coil ID")] - public ValueInput Id { get; private set; } + public ReadOnlyCollection multiInputs { get; private set; } [DoNotSerialize] [PortLabel("Value")] @@ -45,10 +57,19 @@ protected override void Definition() InputTrigger = ControlInput(nameof(InputTrigger), Process); OutputTrigger = ControlOutput(nameof(OutputTrigger)); - Id = ValueInput(nameof(Id), string.Empty); - IsEnabled = ValueInput(nameof(IsEnabled), false); + var _multiInputs = new List(); + + multiInputs = _multiInputs.AsReadOnly(); + + for (var i = 0; i < inputCount; i++) { + var input = ValueInput(i.ToString(), string.Empty); + _multiInputs.Add(input); + + Requirement(input, InputTrigger); + } + + IsEnabled = ValueInput(nameof(IsEnabled), false); - Requirement(Id, InputTrigger); Succession(InputTrigger, OutputTrigger); } @@ -59,10 +80,12 @@ private ControlOutput Process(Flow flow) return OutputTrigger; } - var id = flow.GetValue(Id); var isEnabled = flow.GetValue(IsEnabled); - Gle.SetCoil(id, isEnabled); + foreach (var input in multiInputs) { + var coilId = flow.GetValue(input); + Gle.SetCoil(coilId, isEnabled); + } return OutputTrigger; } diff --git a/Runtime/Nodes/CreateBallUnit.cs b/Runtime/Nodes/CreateBallUnit.cs index 97d751d..7ad5cc1 100644 --- a/Runtime/Nodes/CreateBallUnit.cs +++ b/Runtime/Nodes/CreateBallUnit.cs @@ -21,7 +21,7 @@ namespace VisualPinball.Unity.VisualScripting { [UnitTitle("Create Ball")] - [UnitCategory("Events\\Visual Pinball")] + [UnitCategory("Visual Pinball")] public class CreateBallUnit : GleUnit { [DoNotSerialize] diff --git a/Runtime/Nodes/Display.meta b/Runtime/Nodes/Display.meta new file mode 100644 index 0000000..5e05f55 --- /dev/null +++ b/Runtime/Nodes/Display.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4b4aaa88783ab0440a09c493d57aa178 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/Display/UpdateDisplayUnit.cs b/Runtime/Nodes/Display/UpdateDisplayUnit.cs new file mode 100644 index 0000000..3bc4cc2 --- /dev/null +++ b/Runtime/Nodes/Display/UpdateDisplayUnit.cs @@ -0,0 +1,151 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.Text; +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting +{ + [UnitTitle("Update Display")] + [UnitSurtitle("Gamelogic Engine")] + [UnitCategory("Visual Pinball")] + public class UpdateDisplayUnit : GleUnit + { + [Serialize, Inspectable, UnitHeaderInspectable("ID")] + public DisplayDefinition Display { get; private set; } + + [DoNotSerialize] + [PortLabelHidden] + public ControlInput InputTrigger; + + [DoNotSerialize] + [PortLabelHidden] + public ControlOutput OutputTrigger; + + [DoNotSerialize] + [PortLabel("Numeric")] + public ValueInput NumericInput { get; private set; } + + [DoNotSerialize] + [PortLabel("Text")] + public ValueInput TextInput { get; private set; } + + [DoNotSerialize] + [PortLabel("Segment Data")] + public ValueInput SegmentInput { get; private set; } + + [DoNotSerialize] + [PortLabel("DMD (2-bit)")] + public ValueInput Dmd2Input { get; private set; } + + [DoNotSerialize] + [PortLabel("DMD (4-bit)")] + public ValueInput Dmd4Input { get; private set; } + + [DoNotSerialize] + [PortLabel("DMD (8-bit)")] + public ValueInput Dmd8Input { get; private set; } + + [DoNotSerialize] + [PortLabel("DMD (RGB24)")] + public ValueInput Dmd24Input { get; private set; } + + protected override void Definition() + { + InputTrigger = ControlInput(nameof(InputTrigger), Process); + OutputTrigger = ControlOutput(nameof(OutputTrigger)); + + if (Display != null) { + if (Display.Supports(DisplayFrameFormat.Numeric)) { + NumericInput = ValueInput(nameof(NumericInput)); + } + if (Display.Supports(DisplayFrameFormat.AlphaNumeric)) { + TextInput = ValueInput(nameof(TextInput)); + } + if (Display.Supports(DisplayFrameFormat.Segment)) { + SegmentInput = ValueInput(nameof(SegmentInput)); + } + if (Display.Supports(DisplayFrameFormat.Dmd2)) { + Dmd2Input = ValueInput(nameof(Dmd2Input)); + } + if (Display.Supports(DisplayFrameFormat.Dmd4)) { + Dmd4Input = ValueInput(nameof(Dmd4Input)); + } + if (Display.Supports(DisplayFrameFormat.Dmd8)) { + Dmd8Input = ValueInput(nameof(Dmd8Input)); + } + if (Display.Supports(DisplayFrameFormat.Dmd24)) { + Dmd24Input = ValueInput(nameof(Dmd24Input)); + } + } + + Succession(InputTrigger, OutputTrigger); + } + + private ControlOutput Process(Flow flow) + { + if (!AssertVsGle(flow)) { + throw new InvalidOperationException("Cannot retrieve GLE from unit."); + } + + if (Display != null) { + if (Display.Supports(DisplayFrameFormat.Numeric) && NumericInput.hasValidConnection) { + var numValue = flow.GetValue(NumericInput); + VsGle.DisplayFrame(new DisplayFrameData(Display.Id, DisplayFrameFormat.Numeric, BitConverter.GetBytes(numValue))); + } + if (Display.Supports(DisplayFrameFormat.AlphaNumeric) && flow.IsLocal(TextInput)) { + var strValue = flow.GetValue(TextInput); + if (!string.IsNullOrEmpty(strValue)) { + VsGle.DisplayFrame(new DisplayFrameData(Display.Id, DisplayFrameFormat.AlphaNumeric, Encoding.UTF8.GetBytes(strValue))); + } + } + if (Display.Supports(DisplayFrameFormat.Segment) && SegmentInput.hasValidConnection) { + var byteValue = flow.GetValue(SegmentInput); + if (byteValue is { Length: > 0 }) { + VsGle.DisplayFrame(new DisplayFrameData(Display.Id, DisplayFrameFormat.Segment, byteValue)); + } + } + if (Display.Supports(DisplayFrameFormat.Dmd2) && Dmd2Input.hasValidConnection) { + var byteValue = flow.GetValue(Dmd2Input); + if (byteValue is { Length: > 0 }) { + VsGle.DisplayFrame(new DisplayFrameData(Display.Id, DisplayFrameFormat.Dmd2, byteValue)); + } + } + if (Display.Supports(DisplayFrameFormat.Dmd4) && Dmd4Input.hasValidConnection) { + var byteValue = flow.GetValue(Dmd4Input); + if (byteValue is { Length: > 0 }) { + VsGle.DisplayFrame(new DisplayFrameData(Display.Id, DisplayFrameFormat.Dmd4, byteValue)); + } + } + if (Display.Supports(DisplayFrameFormat.Dmd8) && Dmd8Input.hasValidConnection) { + var byteValue = flow.GetValue(Dmd8Input); + if (byteValue is { Length: > 0 }) { + VsGle.DisplayFrame(new DisplayFrameData(Display.Id, DisplayFrameFormat.Dmd8, byteValue)); + } + } + if (Display.Supports(DisplayFrameFormat.Dmd24) && Dmd24Input.hasValidConnection) { + var byteValue = flow.GetValue(Dmd24Input); + if (byteValue is { Length: > 0 }) { + VsGle.DisplayFrame(new DisplayFrameData(Display.Id, DisplayFrameFormat.Dmd24, byteValue)); + } + } + } + + return OutputTrigger; + } + } +} diff --git a/Runtime/Nodes/Display/UpdateDisplayUnit.cs.meta b/Runtime/Nodes/Display/UpdateDisplayUnit.cs.meta new file mode 100644 index 0000000..1e56842 --- /dev/null +++ b/Runtime/Nodes/Display/UpdateDisplayUnit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f9d549305547ef04ba8a3f0ffc4af51b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/Event.meta b/Runtime/Nodes/Event.meta new file mode 100644 index 0000000..f073979 --- /dev/null +++ b/Runtime/Nodes/Event.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7d5311bf13fb8344eb84e0d7efd211f9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/Event/PinballEventUnit.cs b/Runtime/Nodes/Event/PinballEventUnit.cs new file mode 100644 index 0000000..ac299c4 --- /dev/null +++ b/Runtime/Nodes/Event/PinballEventUnit.cs @@ -0,0 +1,92 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable InconsistentNaming + +using System; +using System.Collections.Generic; +using Unity.VisualScripting; +using UnityEngine; + +namespace VisualPinball.Unity.VisualScripting +{ + /// + /// A special named event with any amount of parameters called manually with the 'Trigger Custom Event' unit. + /// + [UnitTitle("On Pinball Event")] + [UnitCategory("Events/Visual Pinball")] + public class PinballEventUnit : GleEventUnit + { + [Serialize, Inspectable, UnitHeaderInspectable] + public EventDefinition Event { get; set; } + + [SerializeAs(nameof(argumentCount))] + private int _argumentCount; + + [DoNotSerialize] + [Inspectable, UnitHeaderInspectable("Arguments")] + public int argumentCount + { + get => _argumentCount; + set => _argumentCount = Mathf.Clamp(value, 0, 10); + } + + [DoNotSerialize] + public List argumentPorts { get; } = new List(); + + protected override bool register => true; + public override EventHook GetHook(GraphReference reference) => new(VisualScriptingEventNames.PinballEvent); + + protected override void Definition() + { + base.Definition(); + argumentPorts.Clear(); + for (var i = 0; i < argumentCount; i++) { + argumentPorts.Add(ValueOutput("argument_" + i)); + } + } + + protected override bool ShouldTrigger(Flow flow, PinballEventArgs args) + { + return Event.Id.Equals(args.Id); + } + + protected override void AssignArguments(Flow flow, PinballEventArgs args) + { + for (var i = 0; i < argumentCount; i++) { + flow.SetValue(argumentPorts[i], args.Args[i]); + } + } + + public static void Trigger(string id, params object[] args) + { + EventBus.Trigger(VisualScriptingEventNames.PinballEvent, new PinballEventArgs(id, args)); + } + } + + public readonly struct PinballEventArgs + { + public readonly string Id; + + public readonly object[] Args; + + public PinballEventArgs(string id, params object[] args) + { + Id = id; + Args = args; + } + } +} diff --git a/Runtime/Nodes/Event/PinballEventUnit.cs.meta b/Runtime/Nodes/Event/PinballEventUnit.cs.meta new file mode 100644 index 0000000..41a97fb --- /dev/null +++ b/Runtime/Nodes/Event/PinballEventUnit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eb0cb702e7961bf4abc39654881db52e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/Event/TriggerPinballEventUnit.cs b/Runtime/Nodes/Event/TriggerPinballEventUnit.cs new file mode 100644 index 0000000..c53ef1a --- /dev/null +++ b/Runtime/Nodes/Event/TriggerPinballEventUnit.cs @@ -0,0 +1,83 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable InconsistentNaming + +using System.Collections.Generic; +using System.Linq; +using Unity.VisualScripting; +using UnityEngine; + +namespace VisualPinball.Unity.VisualScripting +{ + /// + /// Triggers a pinball event. + /// + [UnitTitle("Trigger Pinball Event")] + [UnitSurtitle("Pinball Event")] + [UnitShortTitle("Trigger")] + [TypeIcon(typeof(CustomEvent))] + [UnitCategory("Events/Visual Pinball")] + public sealed class TriggerPinballEventUnit : GleUnit + { + [Serialize, Inspectable, UnitHeaderInspectable] + public EventDefinition Event { get; set; } + + [SerializeAs(nameof(argumentCount))] + private int _argumentCount; + + [DoNotSerialize] + public List Arguments { get; private set; } + + [DoNotSerialize] + [Inspectable, UnitHeaderInspectable("Arguments")] + public int argumentCount { + get => _argumentCount; + set => _argumentCount = Mathf.Clamp(value, 0, 10); + } + + [DoNotSerialize] + [PortLabelHidden] + public ControlInput InputTrigger { get; private set; } + + [DoNotSerialize] + [PortLabelHidden] + public ControlOutput OutputTrigger { get; private set; } + + protected override void Definition() + { + InputTrigger = ControlInput(nameof(InputTrigger), Trigger); + OutputTrigger = ControlOutput(nameof(OutputTrigger)); + + Arguments = new List(); + for (var i = 0; i < argumentCount; i++) { + var argument = ValueInput("argument_" + i); + Arguments.Add(argument); + Requirement(argument, InputTrigger); + } + + Succession(InputTrigger, OutputTrigger); + } + + private ControlOutput Trigger(Flow flow) + { + var args = Arguments.Select(flow.GetConvertedValue).ToArray(); + PinballEventUnit.Trigger(Event.Id, args); + + return OutputTrigger; + } + } +} diff --git a/Runtime/Nodes/Event/TriggerPinballEventUnit.cs.meta b/Runtime/Nodes/Event/TriggerPinballEventUnit.cs.meta new file mode 100644 index 0000000..4334edc --- /dev/null +++ b/Runtime/Nodes/Event/TriggerPinballEventUnit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e93ef3119452661459c6d560a91b8964 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/GleStartedEventUnit.cs b/Runtime/Nodes/GleStartedEventUnit.cs index ceb0be4..b86afee 100644 --- a/Runtime/Nodes/GleStartedEventUnit.cs +++ b/Runtime/Nodes/GleStartedEventUnit.cs @@ -21,7 +21,7 @@ namespace VisualPinball.Unity.VisualScripting { [UnitTitle("On Gamelogic Engine Started Event")] [UnitCategory("Events\\Visual Pinball")] - public sealed class GleStartedEventUnit : EventUnit + public sealed class GleStartedEventUnit : GleEventUnit { protected override bool register => true; diff --git a/Runtime/Nodes/GleUnit.cs b/Runtime/Nodes/GleUnit.cs index 07eb387..6ab961c 100644 --- a/Runtime/Nodes/GleUnit.cs +++ b/Runtime/Nodes/GleUnit.cs @@ -23,6 +23,30 @@ public abstract class GleEventUnit : EventUnit, IGleUnit { [DoNotSerialize] public List Errors { get; } = new(); + + [DoNotSerialize] + protected IGamelogicEngine Gle; + + [DoNotSerialize] + protected VisualScriptingGamelogicEngine VsGle; + + protected bool AssertGle(Flow flow) + { + if (!Gle.IsUnityNull()) { + return true; + } + Gle = flow.stack.gameObject.GetComponentInParent(); + return Gle != null; + } + + protected bool AssertVsGle(Flow flow) + { + if (!VsGle.IsUnityNull()) { + return true; + } + VsGle = flow.stack.gameObject.GetComponentInParent(); + return VsGle != null; + } } public abstract class GleUnit : Unit, IGleUnit @@ -33,21 +57,33 @@ public abstract class GleUnit : Unit, IGleUnit [DoNotSerialize] protected IGamelogicEngine Gle; + [DoNotSerialize] + protected VisualScriptingGamelogicEngine VsGle; + [DoNotSerialize] protected Player Player; - + protected bool AssertGle(Flow flow) { - if (!UnityObjectUtility.IsUnityNull(Gle)) { + if (!Gle.IsUnityNull()) { return true; } Gle = flow.stack.gameObject.GetComponentInParent(); return Gle != null; } + protected bool AssertVsGle(Flow flow) + { + if (!VsGle.IsUnityNull()) { + return true; + } + VsGle = flow.stack.gameObject.GetComponentInParent(); + return VsGle != null; + } + protected bool AssertPlayer(Flow flow) { - if (!UnityObjectUtility.IsUnityNull(Player)) { + if (!Player.IsUnityNull()) { return true; } Player = flow.stack.gameObject.GetComponentInParent(); diff --git a/Runtime/Nodes/Lamps/GetLampUnit.cs b/Runtime/Nodes/Lamps/GetLampUnit.cs index 22b5da5..4d96d2f 100644 --- a/Runtime/Nodes/Lamps/GetLampUnit.cs +++ b/Runtime/Nodes/Lamps/GetLampUnit.cs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +using System; using Unity.VisualScripting; using UnityEngine; @@ -24,34 +25,45 @@ namespace VisualPinball.Unity.VisualScripting [UnitCategory("Visual Pinball")] public class GetLampUnit : GleUnit { + [Serialize, Inspectable, UnitHeaderInspectable] + public LampDataType DataType { get; set; } + [DoNotSerialize] [PortLabel("Lamp ID")] public ValueInput Id { get; private set; } [DoNotSerialize] - [PortLabel("Value")] public ValueOutput Value { get; private set; } - [DoNotSerialize] - [PortLabel("Is Enabled")] - public ValueOutput IsEnabled { get; private set; } - protected override void Definition() { Id = ValueInput(nameof(Id), string.Empty); - Value = ValueOutput(nameof(Value), GetValue); - IsEnabled = ValueOutput(nameof(IsEnabled), GetEnabled); + switch (DataType) { + case LampDataType.OnOff: + Value = ValueOutput(nameof(Value), GetEnabled); + break; + case LampDataType.Status: + Value = ValueOutput(nameof(Value), GetEnabled); + break; + case LampDataType.Intensity: + Value = ValueOutput(nameof(Value), GetIntensity); + break; + case LampDataType.Color: + Value = ValueOutput(nameof(Value), GetColor); + break; + default: + throw new ArgumentOutOfRangeException(); + } } - private float GetValue(Flow flow) + private float GetIntensity(Flow flow) { if (!AssertGle(flow)) { Debug.LogError("Cannot find GLE."); return 0; } - - return Gle.GetLamp(flow.GetValue(Id)); + return Gle.GetLamp(flow.GetValue(Id)).Intensity; } private bool GetEnabled(Flow flow) @@ -61,7 +73,17 @@ private bool GetEnabled(Flow flow) return false; } - return Gle.GetLamp(flow.GetValue(Id)) > 0; + return Gle.GetLamp(flow.GetValue(Id)).IsOn; + } + + private Color GetColor(Flow flow) + { + if (!AssertGle(flow)) { + Debug.LogError("Cannot find GLE."); + return Color.black; + } + + return Gle.GetLamp(flow.GetValue(Id)).Color.ToUnityColor(); } } } diff --git a/Runtime/Nodes/Lamps/LampDataType.cs b/Runtime/Nodes/Lamps/LampDataType.cs new file mode 100644 index 0000000..b58a93a --- /dev/null +++ b/Runtime/Nodes/Lamps/LampDataType.cs @@ -0,0 +1,23 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +namespace VisualPinball.Unity.VisualScripting +{ + public enum LampDataType + { + OnOff, Status, Intensity, Color, + } +} diff --git a/Runtime/Nodes/Lamps/LampDataType.cs.meta b/Runtime/Nodes/Lamps/LampDataType.cs.meta new file mode 100644 index 0000000..395d58f --- /dev/null +++ b/Runtime/Nodes/Lamps/LampDataType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4ee1294d70683a049a7e50cbc1147674 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/Lamps/LampEventUnit.cs b/Runtime/Nodes/Lamps/LampEventUnit.cs index f579ce5..0840e86 100644 --- a/Runtime/Nodes/Lamps/LampEventUnit.cs +++ b/Runtime/Nodes/Lamps/LampEventUnit.cs @@ -1,31 +1,44 @@ -// Visual Pinball Engine -// Copyright (C) 2022 freezy and VPE Team -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System.Collections.Generic; +using System.Collections.ObjectModel; using Unity.VisualScripting; - +using UnityEngine; + namespace VisualPinball.Unity.VisualScripting { [UnitTitle("On Lamp Changed")] [UnitSurtitle("Gamelogic Engine")] [UnitCategory("Events\\Visual Pinball")] - public sealed class LampEventUnit : GleEventUnit + public sealed class LampEventUnit : GleEventUnit, IMultiInputUnit { + [SerializeAs(nameof(inputCount))] + private int _inputCount = 1; + + [DoNotSerialize] + [Inspectable, UnitHeaderInspectable("Lamp IDs")] + public int inputCount + { + get => _inputCount; + set => _inputCount = Mathf.Clamp(value, 1, 10); + } + [DoNotSerialize] - [PortLabel("Lamp ID")] - public ValueInput Id { get; private set; } + public ReadOnlyCollection multiInputs { get; private set; } [DoNotSerialize] [PortLabel("Intensity")] @@ -46,10 +59,27 @@ protected override void Definition() { base.Definition(); - Id = ValueInput(nameof(Id), string.Empty); + var _multiInputs = new List(); + + multiInputs = _multiInputs.AsReadOnly(); + + for (var i = 0; i < inputCount; i++) { + _multiInputs.Add(ValueInput(i.ToString(), string.Empty)); + } Value = ValueOutput(nameof(Value)); IsEnabled = ValueOutput(nameof(IsEnabled)); + } + + protected override bool ShouldTrigger(Flow flow, LampEventArgs args) + { + foreach (var input in multiInputs) { + if (flow.GetValue(input) == args.Id) { + return true; + } + } + + return false; } protected override void AssignArguments(Flow flow, LampEventArgs args) @@ -57,10 +87,5 @@ protected override void AssignArguments(Flow flow, LampEventArgs args) flow.SetValue(Value, args.Value); flow.SetValue(IsEnabled, args.Value > 0); } - - protected override bool ShouldTrigger(Flow flow, LampEventArgs args) - { - return args.Id == flow.GetValue(Id); - } } } diff --git a/Runtime/Nodes/Lamps/LampIdValue.cs b/Runtime/Nodes/Lamps/LampIdValue.cs new file mode 100644 index 0000000..23a1f0e --- /dev/null +++ b/Runtime/Nodes/Lamps/LampIdValue.cs @@ -0,0 +1,42 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.Collections.Generic; +using Unity.VisualScripting; +using UnityEngine; + +namespace VisualPinball.Unity.VisualScripting +{ + [Serializable] + public struct LampIdValue + { + public string id; + public int value; + + public static LampIdValue FromJson(string json) + { + return JsonUtility.FromJson(json); + } + + public string ToJson() + { + return JsonUtility.ToJson(this); + } + + public static readonly LampIdValue Empty = new LampIdValue { id = string.Empty, value = 0 }; + } +} diff --git a/Runtime/Nodes/Lamps/LampIdValue.cs.meta b/Runtime/Nodes/Lamps/LampIdValue.cs.meta new file mode 100644 index 0000000..798744e --- /dev/null +++ b/Runtime/Nodes/Lamps/LampIdValue.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 525f249f3873543de85effde500fc73c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/Lamps/LampSequenceUnit.cs b/Runtime/Nodes/Lamps/LampSequenceUnit.cs new file mode 100644 index 0000000..3a5c967 --- /dev/null +++ b/Runtime/Nodes/Lamps/LampSequenceUnit.cs @@ -0,0 +1,233 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using Unity.VisualScripting; +using UnityEngine; +using VisualPinball.Engine.Game.Engines; +using Color = VisualPinball.Engine.Math.Color; + +namespace VisualPinball.Unity.VisualScripting +{ + public struct LightComponentMapping + { + public LightComponent lightComponent; + public string id; + + public bool IsValid() => !lightComponent.IsUnityNull(); + } + + [UnitTitle("Lamp Sequence")] + [UnitSurtitle("Gamelogic Engine")] + [UnitCategory("Visual Pinball")] + public class LampSequenceUnit : GleUnit, IMultiInputUnit + { + [Serialize, Inspectable, UnitHeaderInspectable("Value")] + public LampDataType ValueDataType { get; set; } + + [Serialize, Inspectable, UnitHeaderInspectable("Non Step Value")] + public LampDataType NonStepValueDataType { get; set; } + + [DoNotSerialize] + [Inspectable, UnitHeaderInspectable("Lamp IDs")] + public int inputCount + { + get => _inputCount; + set => _inputCount = Mathf.Clamp(value, 1, 10); + } + + [DoNotSerialize] + [PortLabelHidden] + public ControlInput InputTrigger; + + [DoNotSerialize] + [PortLabelHidden] + public ControlOutput OutputTrigger; + + [SerializeAs(nameof(inputCount))] + private int _inputCount = 1; + + [DoNotSerialize] + public ReadOnlyCollection multiInputs { get; private set; } + + [DoNotSerialize] + [PortLabel("Step")] + public ValueInput Step; + + [DoNotSerialize] + public ValueInput Value { get; private set; } + + [DoNotSerialize] + public ValueInput NonStepValue { get; private set; } + + [DoNotSerialize] + private readonly Dictionary _intensityMultipliers = new(); + + private List _lightComponentCache = new(); + private int _currentIndex; + + protected override void Definition() + { + InputTrigger = ControlInput(nameof(InputTrigger), Process); + OutputTrigger = ControlOutput(nameof(OutputTrigger)); + + var mi = new List(); + multiInputs = mi.AsReadOnly(); + + for (var i = 0; i < inputCount; i++) { + var input = ValueInput(i.ToString(), string.Empty); + mi.Add(input); + Requirement(input, InputTrigger); + } + + Step = ValueInput(nameof(Step), 1); + + Value = ValueDataType switch + { + LampDataType.OnOff => ValueInput(nameof(Value), false), + LampDataType.Status => ValueInput(nameof(Value), LampStatus.Off), + LampDataType.Intensity => ValueInput(nameof(Value), 0f), + LampDataType.Color => ValueInput(nameof(Value), UnityEngine.Color.white), + _ => throw new ArgumentOutOfRangeException() + }; + + NonStepValue = NonStepValueDataType switch + { + LampDataType.OnOff => ValueInput(nameof(NonStepValue), false), + LampDataType.Status => ValueInput(nameof(NonStepValue), LampStatus.Off), + LampDataType.Intensity => ValueInput(nameof(NonStepValue), 0f), + LampDataType.Color => ValueInput(nameof(NonStepValue), UnityEngine.Color.white), + _ => throw new ArgumentOutOfRangeException() + }; + + Succession(InputTrigger, OutputTrigger); + + _lightComponentCache.Clear(); + } + + private ControlOutput Process(Flow flow) + { + if (!AssertGle(flow)) { + Debug.LogError("Cannot find GLE."); + return OutputTrigger; + } + + if (!AssertPlayer(flow)) { + Debug.LogError("Cannot find player."); + return OutputTrigger; + } + + foreach (var mapping in _lightComponentCache) { + if (!mapping.IsValid()) { + _lightComponentCache.Clear(); + break; + } + } + + if (_lightComponentCache.Count == 0) { + foreach (var input in multiInputs) { + var lampId = flow.GetValue(input); + + var mappingList = Player.LampMapping.Where(l => l.Id == lampId); + if (mappingList.Any()) { + foreach (var mapping in mappingList) { + UpdateLightComponentCache(mapping.Device, lampId); + } + } + else { + Debug.LogError($"Unknown lamp ID {lampId}."); + _lightComponentCache.Clear(); + + break; + } + } + } + + var stepRaw = flow.GetValue(Step); + + LampDataType dataType; + ValueInput value; + + for (var index = 0; index < _lightComponentCache.Count; index++) { + if (index >= _currentIndex * stepRaw && index < (_currentIndex + 1) * stepRaw) { + dataType = ValueDataType; + value = Value; + } + else { + dataType = NonStepValueDataType; + value = NonStepValue; + } + + var lampApi = Player.Lamp(_lightComponentCache[index].lightComponent); + + switch (dataType) { + case LampDataType.OnOff: + lampApi.OnLamp(flow.GetValue(value) ? LampStatus.On : LampStatus.Off); + break; + case LampDataType.Status: + lampApi.OnLamp(flow.GetValue(value)); + break; + case LampDataType.Intensity: + lampApi.OnLamp(flow.GetValue(value) * GetIntensityMultiplier(_lightComponentCache[index].id)); + break; + case LampDataType.Color: + lampApi.OnLamp(flow.GetValue(value)); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + if (++_currentIndex >= _lightComponentCache.Count / stepRaw) { + _currentIndex = 0; + } + + return OutputTrigger; + } + + private float GetIntensityMultiplier(string id) + { + if (_intensityMultipliers.ContainsKey(id)) { + return _intensityMultipliers[id]; + } + + var mapping = Player.LampMapping.FirstOrDefault(l => l.Id == id); + if (mapping == null) { + Debug.LogError($"Unknown lamp ID {id}."); + _intensityMultipliers[id] = 1; + return 1; + } + + _intensityMultipliers[id] = mapping.Type == LampType.Rgb ? 255 : 1; + return _intensityMultipliers[id]; + } + + private void UpdateLightComponentCache(ILampDeviceComponent device, string id) + { + if (device is LightComponent) { + _lightComponentCache.Add(new LightComponentMapping { lightComponent = device as LightComponent, id = id }); + } + else if (device is LightGroupComponent) { + foreach (var light in (device as LightGroupComponent).Lights) { + UpdateLightComponentCache(light, id); + } + } + } + } +} diff --git a/Runtime/Nodes/Lamps/LampSequenceUnit.cs.meta b/Runtime/Nodes/Lamps/LampSequenceUnit.cs.meta new file mode 100644 index 0000000..7072b6c --- /dev/null +++ b/Runtime/Nodes/Lamps/LampSequenceUnit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f534b9e12134d430db8c6c700be38fc8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/Lamps/SetLampUnit.cs b/Runtime/Nodes/Lamps/SetLampUnit.cs index 97754f3..576bad1 100644 --- a/Runtime/Nodes/Lamps/SetLampUnit.cs +++ b/Runtime/Nodes/Lamps/SetLampUnit.cs @@ -14,17 +14,34 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; using Unity.VisualScripting; using UnityEngine; +using VisualPinball.Engine.Game.Engines; +using Color = VisualPinball.Engine.Math.Color; namespace VisualPinball.Unity.VisualScripting { [UnitShortTitle("Set Lamp")] - [UnitTitle("Set Lamp (ID, Value)")] + [UnitTitle("Set Lamp")] [UnitSurtitle("Gamelogic Engine")] [UnitCategory("Visual Pinball")] - public class SetLampUnit : GleUnit + public class SetLampUnit : GleUnit, IMultiInputUnit { + [Serialize, Inspectable, UnitHeaderInspectable] + public LampDataType DataType { get; set; } + + [DoNotSerialize] + [Inspectable, UnitHeaderInspectable("Lamp IDs")] + public int inputCount + { + get => _inputCount; + set => _inputCount = Mathf.Clamp(value, 1, 10); + } + [DoNotSerialize] [PortLabelHidden] public ControlInput InputTrigger; @@ -33,41 +50,93 @@ public class SetLampUnit : GleUnit [PortLabelHidden] public ControlOutput OutputTrigger; + [SerializeAs(nameof(inputCount))] + private int _inputCount = 1; + [DoNotSerialize] - [PortLabel("Lamp ID")] - public ValueInput Id { get; private set; } + public ReadOnlyCollection multiInputs { get; private set; } [DoNotSerialize] - [PortLabel("Value")] public ValueInput Value { get; private set; } + [DoNotSerialize] + private readonly Dictionary _intensityMultipliers = new(); + protected override void Definition() { InputTrigger = ControlInput(nameof(InputTrigger), Process); OutputTrigger = ControlOutput(nameof(OutputTrigger)); - Id = ValueInput(nameof(Id), string.Empty); - Value = ValueInput(nameof(Value), 0f); + var mi = new List(); + multiInputs = mi.AsReadOnly(); - Requirement(Id, InputTrigger); - Succession(InputTrigger, OutputTrigger); + for (var i = 0; i < inputCount; i++) { + var input = ValueInput(i.ToString(), string.Empty); + mi.Add(input); + Requirement(input, InputTrigger); + } + + Value = DataType switch { + LampDataType.OnOff => ValueInput(nameof(Value), false), + LampDataType.Status => ValueInput(nameof(Value), LampStatus.Off), + LampDataType.Intensity => ValueInput(nameof(Value), 0f), + LampDataType.Color => ValueInput(nameof(Value), UnityEngine.Color.white), + _ => throw new ArgumentOutOfRangeException() + }; + Succession(InputTrigger, OutputTrigger); } private ControlOutput Process(Flow flow) { - if (!AssertGle(flow)) { Debug.LogError("Cannot find GLE."); return OutputTrigger; } - var id = flow.GetValue(Id); - var value = flow.GetValue(Value); + if (!AssertPlayer(flow)) { + Debug.LogError("Cannot find player."); + return OutputTrigger; + } - Gle.SetLamp(id, value * 255f); + foreach (var input in multiInputs) { + var lampId = flow.GetValue(input); + switch (DataType) { + case LampDataType.OnOff: + Player.SetLamp(lampId, flow.GetValue(Value) ? LampStatus.On : LampStatus.Off); + break; + case LampDataType.Status: + Player.SetLamp(lampId, flow.GetValue(Value)); + break; + case LampDataType.Intensity: + Player.SetLamp(lampId, flow.GetValue(Value) * GetIntensityMultiplier(lampId)); + break; + case LampDataType.Color: + Player.SetLamp(lampId, flow.GetValue(Value).ToEngineColor()); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } return OutputTrigger; } + + private float GetIntensityMultiplier(string id) + { + if (_intensityMultipliers.ContainsKey(id)) { + return _intensityMultipliers[id]; + } + + var mapping = Player.LampMapping.FirstOrDefault(l => l.Id == id); + if (mapping == null) { + Debug.LogError($"Unknown lamp ID {id}."); + _intensityMultipliers[id] = 1; + return 1; + } + + _intensityMultipliers[id] = mapping.Type == LampType.Rgb ? 255 : 1; + return _intensityMultipliers[id]; + } } } diff --git a/Runtime/Nodes/Lamps/SetLightSequenceUnit.cs.meta b/Runtime/Nodes/Lamps/SetLightSequenceUnit.cs.meta deleted file mode 100644 index 62cf318..0000000 --- a/Runtime/Nodes/Lamps/SetLightSequenceUnit.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 60a2132e0c1641742b3c4694db33e7e4 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Nodes/Lamps/SetLightUnit.cs.meta b/Runtime/Nodes/Lamps/SetLightUnit.cs.meta deleted file mode 100644 index db927d6..0000000 --- a/Runtime/Nodes/Lamps/SetLightUnit.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6df211a440aa1004e8ec3774ca529cd2 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Nodes/Lamps/SwitchLampUnit.cs b/Runtime/Nodes/Lamps/SwitchLampUnit.cs new file mode 100644 index 0000000..3a24a60 --- /dev/null +++ b/Runtime/Nodes/Lamps/SwitchLampUnit.cs @@ -0,0 +1,178 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using Unity.VisualScripting; +using UnityEngine; +using VisualPinball.Engine.Game.Engines; +using Color = VisualPinball.Engine.Math.Color; + +namespace VisualPinball.Unity.VisualScripting +{ + [UnitShortTitle("Switch Lamp")] + [UnitTitle("Switch Lamp (ID, match value)")] + [UnitSurtitle("Gamelogic Engine")] + [UnitCategory("Visual Pinball")] + public class SwitchLampUnit : GleUnit, IMultiInputUnit + { + [Serialize, Inspectable, UnitHeaderInspectable("Match")] + public LampDataType MatchDataType { get; set; } + + [Serialize, Inspectable, UnitHeaderInspectable("Non Match")] + public LampDataType NonMatchDataType { get; set; } + + [DoNotSerialize] + [Inspectable, UnitHeaderInspectable("Lamp IDs")] + public int inputCount + { + get => _inputCount; + set => _inputCount = Mathf.Clamp(value, 1, 10); + } + + [DoNotSerialize] + [PortLabelHidden] + public ControlInput InputTrigger; + + [DoNotSerialize] + [PortLabelHidden] + public ControlOutput OutputTrigger; + + [SerializeAs(nameof(inputCount))] + private int _inputCount = 1; + + [DoNotSerialize] + public ReadOnlyCollection multiInputs { get; private set; } + + [DoNotSerialize] + [PortLabel("Source Value")] + public ValueInput SourceValue { get; private set; } + + [DoNotSerialize] + public ValueInput Match { get; private set; } + + [DoNotSerialize] + public ValueInput NonMatch { get; private set; } + + [DoNotSerialize] + private readonly Dictionary _intensityMultipliers = new(); + + private Dictionary _lampIdValueCache = new Dictionary(); + + protected override void Definition() + { + InputTrigger = ControlInput(nameof(InputTrigger), Process); + OutputTrigger = ControlOutput(nameof(OutputTrigger)); + + SourceValue = ValueInput(nameof(SourceValue)); + + var mi = new List(); + multiInputs = mi.AsReadOnly(); + + for (var i = 0; i < inputCount; i++) { + var input = ValueInput(i.ToString(), LampIdValue.Empty.ToJson()); + mi.Add(input); + Requirement(input, InputTrigger); + } + + _lampIdValueCache.Clear(); + + Match = MatchDataType switch { + LampDataType.OnOff => ValueInput(nameof(Match), false), + LampDataType.Status => ValueInput(nameof(Match), LampStatus.Off), + LampDataType.Intensity => ValueInput(nameof(Match), 0f), + LampDataType.Color => ValueInput(nameof(Match), UnityEngine.Color.white), + _ => throw new ArgumentOutOfRangeException() + }; + + NonMatch = NonMatchDataType switch { + LampDataType.OnOff => ValueInput(nameof(NonMatch), false), + LampDataType.Status => ValueInput(nameof(NonMatch), LampStatus.Off), + LampDataType.Intensity => ValueInput(nameof(NonMatch), 0f), + LampDataType.Color => ValueInput(nameof(NonMatch), UnityEngine.Color.white), + _ => throw new ArgumentOutOfRangeException() + }; + + Succession(InputTrigger, OutputTrigger); + } + + private ControlOutput Process(Flow flow) + { + if (!AssertGle(flow)) { + Debug.LogError("Cannot find GLE."); + return OutputTrigger; + } + + if (!AssertPlayer(flow)) { + Debug.LogError("Cannot find player."); + return OutputTrigger; + } + + var sourceValue = flow.GetValue(SourceValue); + + foreach (var input in multiInputs) { + var json = flow.GetValue(input); + + if (!_lampIdValueCache.ContainsKey(json.GetHashCode())) { + _lampIdValueCache[json.GetHashCode()] = LampIdValue.FromJson(json); + } + + var lampIdValue = _lampIdValueCache[json.GetHashCode()]; + + var dataType = lampIdValue.value == sourceValue ? MatchDataType : NonMatchDataType; + var value = lampIdValue.value == sourceValue ? Match : NonMatch; + + switch (dataType) { + case LampDataType.OnOff: + Player.SetLamp(lampIdValue.id, flow.GetValue(value) ? LampStatus.On : LampStatus.Off); + break; + case LampDataType.Status: + Player.SetLamp(lampIdValue.id, flow.GetValue(value)); + break; + case LampDataType.Intensity: + Player.SetLamp(lampIdValue.id, flow.GetValue(value) * GetIntensityMultiplier(lampIdValue.id)); + break; + case LampDataType.Color: + Player.SetLamp(lampIdValue.id, flow.GetValue(value).ToEngineColor()); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + return OutputTrigger; + } + + private float GetIntensityMultiplier(string id) + { + if (_intensityMultipliers.ContainsKey(id)) { + return _intensityMultipliers[id]; + } + + var mapping = Player.LampMapping.FirstOrDefault(l => l.Id == id); + if (mapping == null) { + Debug.LogError($"Unknown lamp ID {id}."); + _intensityMultipliers[id] = 1; + return 1; + } + + _intensityMultipliers[id] = mapping.Type == LampType.Rgb ? 255 : 1; + return _intensityMultipliers[id]; + } + } +} diff --git a/Runtime/Nodes/Lamps/SwitchLampUnit.cs.meta b/Runtime/Nodes/Lamps/SwitchLampUnit.cs.meta new file mode 100644 index 0000000..21f19df --- /dev/null +++ b/Runtime/Nodes/Lamps/SwitchLampUnit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c6f6ca79d45bb4133845d06126820a47 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/PlayerState.meta b/Runtime/Nodes/PlayerState.meta new file mode 100644 index 0000000..4918ac4 --- /dev/null +++ b/Runtime/Nodes/PlayerState.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6d6c8897d98d2ac45b5beb287485da78 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/PlayerState/ChangePlayerStateUnit.cs b/Runtime/Nodes/PlayerState/ChangePlayerStateUnit.cs new file mode 100644 index 0000000..20b97e5 --- /dev/null +++ b/Runtime/Nodes/PlayerState/ChangePlayerStateUnit.cs @@ -0,0 +1,87 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.Linq; +using NLog; +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting +{ + [UnitTitle("Change Player State")] + [UnitSurtitle("Player State")] + [UnitCategory("Visual Pinball/Variables")] + public class ChangePlayerStateUnit : GleUnit + { + [Serialize, Inspectable, UnitHeaderInspectable("Next Player")] + public bool NextPlayer { get; set; } + + [DoNotSerialize] + [PortLabelHidden] + public ControlInput InputTrigger; + + [DoNotSerialize] + [PortLabelHidden] + public ControlOutput OutputTrigger; + + [DoNotSerialize] + [PortLabel("Player ID")] + public ValueInput PlayerId { get; private set; } + + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + + protected override void Definition() + { + InputTrigger = ControlInput(nameof(InputTrigger), Process); + OutputTrigger = ControlOutput(nameof(OutputTrigger)); + + if (!NextPlayer) { + PlayerId = ValueInput(nameof(PlayerId), 0); + Requirement(PlayerId, InputTrigger); + } + + Succession(InputTrigger, OutputTrigger); + } + + private ControlOutput Process(Flow flow) + { + if (!AssertVsGle(flow)) { + throw new InvalidOperationException("Cannot retrieve GLE from unit."); + } + + int playerId; + if (NextPlayer) { + var lastPlayer = VsGle.PlayerStates.Keys.Max(); + if (VsGle.CurrentPlayerState.Id == lastPlayer) { + playerId = VsGle.PlayerStates.Keys.Min(); + + } else if (VsGle.PlayerStates.ContainsKey(VsGle.CurrentPlayerState.Id + 1)) { + playerId = VsGle.CurrentPlayerState.Id + 1; + + } else { + Logger.Warn($"Non-existent next player {VsGle.CurrentPlayerState.Id + 1}."); + playerId = VsGle.CurrentPlayerState.Id; + } + } else { + playerId = flow.GetValue(PlayerId); + } + + VsGle.SetCurrentPlayer(playerId); + + return OutputTrigger; + } + } +} diff --git a/Runtime/Nodes/PlayerState/ChangePlayerStateUnit.cs.meta b/Runtime/Nodes/PlayerState/ChangePlayerStateUnit.cs.meta new file mode 100644 index 0000000..6051dab --- /dev/null +++ b/Runtime/Nodes/PlayerState/ChangePlayerStateUnit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2ce86bae940d6e24c96620a150f330cc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/PlayerState/CreatePlayerStateUnit.cs b/Runtime/Nodes/PlayerState/CreatePlayerStateUnit.cs new file mode 100644 index 0000000..69858b3 --- /dev/null +++ b/Runtime/Nodes/PlayerState/CreatePlayerStateUnit.cs @@ -0,0 +1,94 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.Linq; +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting +{ + [UnitTitle("Create Player State")] + [UnitSurtitle("Player State")] + [UnitCategory("Visual Pinball/Variables")] + public class CreatePlayerStateUnit : GleUnit + { + [Serialize, Inspectable, UnitHeaderInspectable("Auto-increment")] + public bool AutoIncrement { get; set; } + + [DoNotSerialize] + [PortLabelHidden] + public ControlInput InputTrigger; + + [DoNotSerialize] + [PortLabelHidden] + public ControlOutput OutputTrigger; + + [DoNotSerialize] + [PortLabel("Player ID")] + public ValueInput PlayerId { get; private set; } + + [DoNotSerialize] + [PortLabel("Set as Active")] + public ValueInput SetAsActive { get; set; } + + [DoNotSerialize] + [PortLabel("Destroy Previous")] + public ValueInput DestroyPrevious { get; set; } + + protected override void Definition() + { + InputTrigger = ControlInput(nameof(InputTrigger), Process); + OutputTrigger = ControlOutput(nameof(OutputTrigger)); + + if (!AutoIncrement) { + PlayerId = ValueInput(nameof(PlayerId), 0); + Requirement(PlayerId, InputTrigger); + } + + SetAsActive = ValueInput(nameof(SetAsActive), false); + DestroyPrevious = ValueInput(nameof(DestroyPrevious), false); + + Succession(InputTrigger, OutputTrigger); + } + + private ControlOutput Process(Flow flow) + { + if (!AssertVsGle(flow)) { + throw new InvalidOperationException("Cannot retrieve GLE from unit."); + } + + // destroy previous + if (flow.GetValue(DestroyPrevious)) { + VsGle.DestroyPlayerStates(); + } + + // determine new player id + var newPlayerId = AutoIncrement && VsGle.PlayerStates.Count > 0 + ? VsGle.PlayerStates.Keys.Max() + 1 + : VsGle.PlayerStates.Count == 0 ? 0 : flow.GetValue(PlayerId); + + // create new state + VsGle.CreatePlayerState(newPlayerId); + + // set as active + if (flow.GetValue(SetAsActive)) { + VsGle.SetCurrentPlayer(newPlayerId, flow.GetValue(DestroyPrevious)); + } + + return OutputTrigger; + } + } +} diff --git a/Runtime/Nodes/PlayerState/CreatePlayerStateUnit.cs.meta b/Runtime/Nodes/PlayerState/CreatePlayerStateUnit.cs.meta new file mode 100644 index 0000000..6789ed6 --- /dev/null +++ b/Runtime/Nodes/PlayerState/CreatePlayerStateUnit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 49dce4f81de192943af7fd6302c70c8e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/PlayerState/GetPlayerIdUnit.cs b/Runtime/Nodes/PlayerState/GetPlayerIdUnit.cs new file mode 100644 index 0000000..70921d3 --- /dev/null +++ b/Runtime/Nodes/PlayerState/GetPlayerIdUnit.cs @@ -0,0 +1,58 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.Linq; +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting +{ + [UnitTitle("Get Player ID")] + [UnitSurtitle("Player State")] + [UnitCategory("Visual Pinball/Variables")] + public class GetPlayerIdUnit : GleUnit + { + [Serialize, Inspectable, UnitHeaderInspectable] + public WhichPlayer Which { get; set; } + + [DoNotSerialize, PortLabel("Player ID"), Inspectable] + public ValueOutput PlayerId { get; private set; } + + protected override void Definition() + { + PlayerId = ValueOutput(nameof(PlayerId), GetPlayerId); + } + + private int GetPlayerId(Flow flow) + { + if (!AssertVsGle(flow)) { + throw new InvalidOperationException("Cannot retrieve GLE from unit."); + } + + return Which switch { + WhichPlayer.First => VsGle.PlayerStates.Keys.Min(), + WhichPlayer.Last => VsGle.PlayerStates.Keys.Max(), + WhichPlayer.Current => VsGle.CurrentPlayerState.Id, + _ => throw new ArgumentOutOfRangeException() + }; + } + } + + public enum WhichPlayer + { + Current, First, Last + } +} diff --git a/Runtime/Nodes/PlayerState/GetPlayerIdUnit.cs.meta b/Runtime/Nodes/PlayerState/GetPlayerIdUnit.cs.meta new file mode 100644 index 0000000..448a913 --- /dev/null +++ b/Runtime/Nodes/PlayerState/GetPlayerIdUnit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 17f6b99539e3a5944b08a9b1d16f7ddf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/PlayerState/GetVariableUnit.cs b/Runtime/Nodes/PlayerState/GetVariableUnit.cs new file mode 100644 index 0000000..7a46ef3 --- /dev/null +++ b/Runtime/Nodes/PlayerState/GetVariableUnit.cs @@ -0,0 +1,101 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting +{ + [UnitTitle("Get Player Variable")] + [UnitSurtitle("Player State")] + [UnitCategory("Visual Pinball/Variables")] + public class GetPlayerVariableUnit : GetVariableUnit + { + [Serialize, Inspectable, UnitHeaderInspectable] + public PlayerVariableDefinition Variable { get; set; } + + protected override VariableDefinition VariableDefinition => Variable; + protected override State State => VsGle.CurrentPlayerState; + } + + [UnitTitle("Get Table Variable")] + [UnitSurtitle("Table State")] + [UnitCategory("Visual Pinball/Variables")] + public class GetTableVariableUnit : GetVariableUnit + { + [Serialize, Inspectable, UnitHeaderInspectable] + public TableVariableDefinition Variable { get; set; } + protected override VariableDefinition VariableDefinition => Variable; + + protected override State State => VsGle.TableState; + } + + public abstract class GetVariableUnit : GleUnit + { + [DoNotSerialize, PortLabel("Value"), Inspectable] + public ValueOutput Value { get; private set; } + + protected abstract State State { get; } + protected abstract VariableDefinition VariableDefinition { get; } + + protected override void Definition() + { + if (VariableDefinition == null) { + return; + } + + Value = VariableDefinition.Type switch { + VariableType.String => ValueOutput(nameof(Value), GetString), + VariableType.Integer => ValueOutput(nameof(Value), GetInt), + VariableType.Float => ValueOutput(nameof(Value), GetFloat), + VariableType.Boolean => ValueOutput(nameof(Value), GetBool), + _ => throw new ArgumentOutOfRangeException() + }; + } + + private string GetString(Flow flow) + { + if (!AssertVsGle(flow)) { + throw new InvalidOperationException("Cannot retrieve GLE from unit."); + } + return State.Get(VariableDefinition.Id); + } + + private bool GetBool(Flow flow) + { + if (!AssertVsGle(flow)) { + throw new InvalidOperationException("Cannot retrieve GLE from unit."); + } + return (bool)State.Get(VariableDefinition.Id); + } + + private float GetFloat(Flow flow) + { + if (!AssertVsGle(flow)) { + throw new InvalidOperationException("Cannot retrieve GLE from unit."); + } + return (float)State.Get(VariableDefinition.Id); + } + + private int GetInt(Flow flow) + { + if (!AssertVsGle(flow)) { + throw new InvalidOperationException("Cannot retrieve GLE from unit."); + } + return (int)State.Get(VariableDefinition.Id); + } + } +} diff --git a/Runtime/Nodes/PlayerState/GetVariableUnit.cs.meta b/Runtime/Nodes/PlayerState/GetVariableUnit.cs.meta new file mode 100644 index 0000000..58f517f --- /dev/null +++ b/Runtime/Nodes/PlayerState/GetVariableUnit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8308019eab154104b8ba31ce6e500090 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/PlayerState/IncreaseVariableUnit.cs b/Runtime/Nodes/PlayerState/IncreaseVariableUnit.cs new file mode 100644 index 0000000..55fc942 --- /dev/null +++ b/Runtime/Nodes/PlayerState/IncreaseVariableUnit.cs @@ -0,0 +1,133 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting +{ + [UnitTitle("Increase Player Variable")] + [UnitSurtitle("Player State")] + [UnitCategory("Visual Pinball/Variables")] + public class IncreasePlayerVariableUnit : IncreaseVariableUnit + { + [Serialize, Inspectable, UnitHeaderInspectable] + public PlayerVariableDefinition Variable { get; set; } + + protected override State State => VsGle.CurrentPlayerState; + protected override VariableDefinition VariableDefinition => Variable; + } + + [UnitTitle("Increase Table Variable")] + [UnitSurtitle("Table State")] + [UnitCategory("Visual Pinball/Variables")] + public class IncreaseTableVariableUnit : IncreaseVariableUnit + { + [Serialize, Inspectable, UnitHeaderInspectable] + public TableVariableDefinition Variable { get; set; } + + protected override State State => VsGle.TableState; + protected override VariableDefinition VariableDefinition => Variable; + } + + public abstract class IncreaseVariableUnit : GleUnit + { + [DoNotSerialize, PortLabelHidden] + public ControlInput InputTrigger; + + [DoNotSerialize, PortLabelHidden] + public ControlOutput OutputTrigger; + + [DoNotSerialize, PortLabel("Increase By"), Inspectable] + public ValueInput Value { get; private set; } + + [DoNotSerialize, PortLabel("Updated Value"), Inspectable] + public ValueOutput OutputValue { get; private set; } + + protected abstract State State { get; } + protected abstract VariableDefinition VariableDefinition { get; } + + protected override void Definition() + { + InputTrigger = ControlInput(nameof(InputTrigger), Process); + OutputTrigger = ControlOutput(nameof(OutputTrigger)); + + Succession(InputTrigger, OutputTrigger); + + if (VariableDefinition == null) { + return; + } + + Value = VariableDefinition.Type switch { + VariableType.Integer => ValueInput(nameof(Value), 0), + VariableType.Float => ValueInput(nameof(Value), 0f), + VariableType.Boolean => ValueInput(nameof(Value), false), + VariableType.String => ValueInput(nameof(Value), string.Empty), + _ => throw new ArgumentOutOfRangeException() + }; + + OutputValue = VariableDefinition.Type switch { + VariableType.Integer => ValueOutput(nameof(Value)), + VariableType.Float => ValueOutput(nameof(Value)), + VariableType.Boolean => ValueOutput(nameof(Value)), + VariableType.String => ValueOutput(nameof(Value)), + _ => throw new ArgumentOutOfRangeException() + }; + Requirement(Value, InputTrigger); + } + + private ControlOutput Process(Flow flow) + { + if (!AssertVsGle(flow)) { + throw new InvalidOperationException("Cannot retrieve GLE from unit."); + } + + switch (VariableDefinition.Type) { + case VariableType.Integer: { + var current = (int)State.Get(VariableDefinition.Id); + State.Set(VariableDefinition.Id, new Integer(current + flow.GetValue(Value))); + flow.SetValue(OutputValue, current + flow.GetValue(Value)); + break; + } + case VariableType.Float: { + var current = (float)State.Get(VariableDefinition.Id); + State.Set(VariableDefinition.Id, new Float(current + flow.GetValue(Value))); + flow.SetValue(OutputValue, current + flow.GetValue(Value)); + break; + } + case VariableType.Boolean: { + if (flow.GetValue(Value)) { + var current = (bool)State.Get(VariableDefinition.Id); + State.Set(VariableDefinition.Id, new Bool(!current)); + flow.SetValue(OutputValue, !current); + } + break; + } + case VariableType.String: { + var current = State.Get(VariableDefinition.Id); + var next = current + flow.GetValue(Value); + State.Set(VariableDefinition.Id, next); + flow.SetValue(OutputValue, next); + break; + } + default: + throw new ArgumentOutOfRangeException(); + } + + return OutputTrigger; + } + } +} diff --git a/Runtime/Nodes/PlayerState/IncreaseVariableUnit.cs.meta b/Runtime/Nodes/PlayerState/IncreaseVariableUnit.cs.meta new file mode 100644 index 0000000..7f1c027 --- /dev/null +++ b/Runtime/Nodes/PlayerState/IncreaseVariableUnit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5cafbd98b8fb37445857dae9786b4801 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/PlayerState/SetVariableUnit.cs b/Runtime/Nodes/PlayerState/SetVariableUnit.cs new file mode 100644 index 0000000..b7f6c5a --- /dev/null +++ b/Runtime/Nodes/PlayerState/SetVariableUnit.cs @@ -0,0 +1,123 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using Unity.VisualScripting; +using UnityEngine; + +namespace VisualPinball.Unity.VisualScripting +{ + [UnitTitle("Set Player Variable")] + [UnitSurtitle("Player State")] + [UnitCategory("Visual Pinball/Variables")] + public class SetPlayerVariableUnit : SetVariableUnit + { + [Serialize, Inspectable, UnitHeaderInspectable] + public PlayerVariableDefinition Variable { get; set; } + + protected override State State => VsGle.CurrentPlayerState; + protected override VariableDefinition VariableDefinition => Variable; + } + + [UnitTitle("Set Table Variable")] + [UnitSurtitle("Table State")] + [UnitCategory("Visual Pinball/Variables")] + public class SetTableVariableUnit : SetVariableUnit + { + [Serialize, Inspectable, UnitHeaderInspectable] + public TableVariableDefinition Variable { get; set; } + + protected override State State => VsGle.TableState; + protected override VariableDefinition VariableDefinition => Variable; + } + + public abstract class SetVariableUnit : GleUnit + { + [DoNotSerialize, PortLabelHidden] + public ControlInput InputTrigger; + + [DoNotSerialize, PortLabelHidden] + public ControlOutput OutputTrigger; + + [DoNotSerialize, PortLabel("Value"), Inspectable] + public ValueInput Value { get; private set; } + + [DoNotSerialize, PortLabel("Value"), Inspectable] + public ValueOutput OutputValue { get; private set; } + + protected abstract State State { get; } + protected abstract VariableDefinition VariableDefinition { get; } + + protected override void Definition() + { + InputTrigger = ControlInput(nameof(InputTrigger), Process); + OutputTrigger = ControlOutput(nameof(OutputTrigger)); + + Succession(InputTrigger, OutputTrigger); + + if (VariableDefinition == null) { + return; + } + + Value = VariableDefinition.Type switch { + VariableType.String => ValueInput(nameof(Value), string.Empty), + VariableType.Integer => ValueInput(nameof(Value), 0), + VariableType.Float => ValueInput(nameof(Value), 0f), + VariableType.Boolean => ValueInput(nameof(Value), false), + _ => throw new ArgumentOutOfRangeException() + }; + + OutputValue = VariableDefinition.Type switch { + VariableType.String => ValueOutput(nameof(Value)), + VariableType.Integer => ValueOutput(nameof(Value)), + VariableType.Float => ValueOutput(nameof(Value)), + VariableType.Boolean => ValueOutput(nameof(Value)), + _ => throw new ArgumentOutOfRangeException() + }; + Requirement(Value, InputTrigger); + } + + private ControlOutput Process(Flow flow) + { + if (!AssertVsGle(flow)) { + throw new InvalidOperationException("Cannot retrieve GLE from unit."); + } + + switch (VariableDefinition.Type) { + case VariableType.String: + State.Set(VariableDefinition.Id, flow.GetValue(Value)); + flow.SetValue(OutputValue, flow.GetValue(Value)); + break; + case VariableType.Integer: + State.Set(VariableDefinition.Id, new Integer(flow.GetValue(Value))); + flow.SetValue(OutputValue, flow.GetValue(Value)); + break; + case VariableType.Float: + State.Set(VariableDefinition.Id, new Float(flow.GetValue(Value))); + flow.SetValue(OutputValue, flow.GetValue(Value)); + break; + case VariableType.Boolean: + State.Set(VariableDefinition.Id, new Bool(flow.GetValue(Value))); + flow.SetValue(OutputValue, flow.GetValue(Value)); + break; + default: + throw new ArgumentOutOfRangeException(); + } + + return OutputTrigger; + } + } +} diff --git a/Runtime/Nodes/PlayerState/SetVariableUnit.cs.meta b/Runtime/Nodes/PlayerState/SetVariableUnit.cs.meta new file mode 100644 index 0000000..430ec06 --- /dev/null +++ b/Runtime/Nodes/PlayerState/SetVariableUnit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a525259e500cec348a2b697b863409bf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/PlayerState/VariableChangedEventUnit.cs b/Runtime/Nodes/PlayerState/VariableChangedEventUnit.cs new file mode 100644 index 0000000..0056ece --- /dev/null +++ b/Runtime/Nodes/PlayerState/VariableChangedEventUnit.cs @@ -0,0 +1,121 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using Unity.VisualScripting; + +namespace VisualPinball.Unity.VisualScripting +{ + [UnitTitle("On Player Variable Changed")] + [UnitSurtitle("Player State")] + [UnitCategory("Events\\Visual Pinball")] + public class PlayerVariableChangedEventUnit : VariableChangedEventUnit + { + [Serialize, Inspectable, UnitHeaderInspectable] + public PlayerVariableDefinition Variable { get; set; } + + protected override State State => VsGle.CurrentPlayerState; + protected override VariableDefinition VariableDefinition => Variable; + protected override string EventHookName => VisualScriptingEventNames.PlayerVariableChanged; + } + + [UnitTitle("On Table Variable Changed")] + [UnitSurtitle("Table State")] + [UnitCategory("Events\\Visual Pinball")] + public class TableVariableChangedEventUnit : VariableChangedEventUnit + { + [Serialize, Inspectable, UnitHeaderInspectable] + public TableVariableDefinition Variable { get; set; } + + protected override State State => VsGle.TableState; + protected override VariableDefinition VariableDefinition => Variable; + protected override string EventHookName => VisualScriptingEventNames.TableVariableChanged; + } + + public abstract class VariableChangedEventUnit : GleEventUnit + { + [DoNotSerialize, PortLabel("Old Value"), Inspectable] + public ValueOutput OldValue { get; private set; } + + [DoNotSerialize, PortLabel("New Value"), Inspectable] + public ValueOutput NewValue { get; private set; } + + public override EventHook GetHook(GraphReference reference) => new(EventHookName); + protected override bool register => true; + + protected abstract State State { get; } + protected abstract VariableDefinition VariableDefinition { get; } + protected abstract string EventHookName { get; } + + protected override void Definition() + { + base.Definition(); + + if (VariableDefinition == null) { + return; + } + + OldValue = VariableDefinition.Type switch { + VariableType.String => ValueOutput(nameof(OldValue)), + VariableType.Integer => ValueOutput(nameof(OldValue)), + VariableType.Float => ValueOutput(nameof(OldValue)), + VariableType.Boolean => ValueOutput(nameof(OldValue)), + _ => throw new ArgumentOutOfRangeException() + }; + + NewValue = VariableDefinition.Type switch { + VariableType.String => ValueOutput(nameof(NewValue)), + VariableType.Integer => ValueOutput(nameof(NewValue)), + VariableType.Float => ValueOutput(nameof(NewValue)), + VariableType.Boolean => ValueOutput(nameof(NewValue)), + _ => throw new ArgumentOutOfRangeException() + }; + } + + protected override bool ShouldTrigger(Flow flow, VariableChangedArgs args) + { + return VariableDefinition.Id == args.VariableId; + } + + protected override void AssignArguments(Flow flow, VariableChangedArgs args) + { + if (!AssertVsGle(flow)) { + throw new InvalidOperationException("Cannot retrieve GLE from unit."); + } + + switch (VariableDefinition.Type) { + case VariableType.String: + flow.SetValue(OldValue, (string)args.OldValue); + flow.SetValue(NewValue, (string)args.NewValue); + break; + case VariableType.Integer: + flow.SetValue(OldValue, (int)(Integer)args.OldValue); + flow.SetValue(NewValue, (int)(Integer)args.NewValue); + break; + case VariableType.Float: + flow.SetValue(OldValue, (float)(Float)args.OldValue); + flow.SetValue(NewValue, (float)(Float)args.NewValue); + break; + case VariableType.Boolean: + flow.SetValue(OldValue, (bool)(Bool)args.OldValue); + flow.SetValue(NewValue, (bool)(Bool)args.NewValue); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + } +} diff --git a/Runtime/Nodes/PlayerState/VariableChangedEventUnit.cs.meta b/Runtime/Nodes/PlayerState/VariableChangedEventUnit.cs.meta new file mode 100644 index 0000000..f766c1c --- /dev/null +++ b/Runtime/Nodes/PlayerState/VariableChangedEventUnit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8d68d23dd11076b4a9ba3c791d2b29ae +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/Switches/AllSwitchesEnabledEventUnit.cs b/Runtime/Nodes/Switches/AllSwitchesEnabledEventUnit.cs new file mode 100644 index 0000000..63d5d4b --- /dev/null +++ b/Runtime/Nodes/Switches/AllSwitchesEnabledEventUnit.cs @@ -0,0 +1,81 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Unity.VisualScripting; +using UnityEngine; + +namespace VisualPinball.Unity.VisualScripting +{ + [UnitTitle("On All Switches Enabled")] + [UnitSurtitle("Gamelogic Engine")] + [UnitCategory("Events\\Visual Pinball")] + public class AllSwitchesEnabledEventUnit : GleEventUnit, IMultiInputUnit + { + [SerializeAs(nameof(inputCount))] + private int _inputCount = 1; + + [DoNotSerialize] + [Inspectable, UnitHeaderInspectable("Switch IDs")] + public int inputCount + { + get => _inputCount; + set => _inputCount = Mathf.Clamp(value, 1, 10); + } + + [DoNotSerialize] + public ReadOnlyCollection multiInputs { get; private set; } + + [DoNotSerialize] + protected override bool register => true; + + public override EventHook GetHook(GraphReference reference) => new EventHook(VisualScriptingEventNames.SwitchEvent); + + protected override void Definition() + { + base.Definition(); + + var _multiInputs = new List(); + + multiInputs = _multiInputs.AsReadOnly(); + + for (var i = 0; i < inputCount; i++) { + _multiInputs.Add(ValueInput(i.ToString(), string.Empty)); + } + } + + protected override bool ShouldTrigger(Flow flow, SwitchEventArgs2 args) + { + if (!AssertGle(flow)) { + Debug.LogError("Cannot find GLE."); + return false; + } + + var validSwitch = false; + foreach(var input in multiInputs) { + var swId = flow.GetValue(input); + if (swId == args.Id) { + validSwitch = true; + } + if (!Gle.GetSwitch(swId)) { + return false; + } + } + return validSwitch; + } + } +} diff --git a/Runtime/Nodes/Switches/AllSwitchesEnabledEventUnit.cs.meta b/Runtime/Nodes/Switches/AllSwitchesEnabledEventUnit.cs.meta new file mode 100644 index 0000000..1826117 --- /dev/null +++ b/Runtime/Nodes/Switches/AllSwitchesEnabledEventUnit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3c328f0dcce0b9a46b827d189ffd180a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/Switches/GetSwitchUnit.cs b/Runtime/Nodes/Switches/GetSwitchUnit.cs new file mode 100644 index 0000000..1cc8585 --- /dev/null +++ b/Runtime/Nodes/Switches/GetSwitchUnit.cs @@ -0,0 +1,51 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using Unity.VisualScripting; +using UnityEngine; + +namespace VisualPinball.Unity.VisualScripting +{ + [UnitTitle("Get Switch Value")] + [UnitSurtitle("Gamelogic Engine")] + [UnitCategory("Visual Pinball")] + public class GetSwitchUnit : GleUnit + { + [DoNotSerialize] + [PortLabel("Switch ID")] + public ValueInput Id { get; private set; } + + [DoNotSerialize] + [PortLabel("Is Enabled")] + public ValueOutput IsEnabled { get; private set; } + + protected override void Definition() + { + Id = ValueInput(nameof(Id), string.Empty); + IsEnabled = ValueOutput(nameof(IsEnabled), GetEnabled); + } + + private bool GetEnabled(Flow flow) + { + if (!AssertGle(flow)) { + Debug.LogError("Cannot find GLE."); + return false; + } + + return Gle.GetSwitch(flow.GetValue(Id)); + } + } +} diff --git a/Runtime/Nodes/Switches/GetSwitchUnit.cs.meta b/Runtime/Nodes/Switches/GetSwitchUnit.cs.meta new file mode 100644 index 0000000..5d17946 --- /dev/null +++ b/Runtime/Nodes/Switches/GetSwitchUnit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fcc0ca29871c04d7fa61243e08eab438 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/Lamps/SetLightSequenceUnit.cs b/Runtime/Nodes/Switches/PulseSwitchUnit.cs similarity index 51% rename from Runtime/Nodes/Lamps/SetLightSequenceUnit.cs rename to Runtime/Nodes/Switches/PulseSwitchUnit.cs index a1ae9a5..da84be9 100644 --- a/Runtime/Nodes/Lamps/SetLightSequenceUnit.cs +++ b/Runtime/Nodes/Switches/PulseSwitchUnit.cs @@ -1,95 +1,99 @@ -// Visual Pinball Engine -// Copyright (C) 2022 freezy and VPE Team -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -using Unity.VisualScripting; -using UnityEngine; -using VisualPinball.Engine.Math; - -namespace VisualPinball.Unity.VisualScripting -{ - [UnitTitle("Set Light Sequence")] - [UnitSurtitle("Scene")] - [UnitCategory("Visual Pinball")] - public class SetLightSequenceUnit : GleUnit - { - [DoNotSerialize] - [PortLabelHidden] - public ControlInput InputTrigger; - - [DoNotSerialize] - [PortLabelHidden] - public ControlOutput OutputTrigger; - - [DoNotSerialize] - [PortLabel("Light Group")] - public ValueInput LightGroup; - - [DoNotSerialize] - [PortLabel("Intensity")] - public ValueInput Value; - - [DoNotSerialize] - [PortLabel("Color Channel")] - public ValueInput ColorChannel; - - [DoNotSerialize] - [PortLabel("Step")] - public ValueInput Step; - - private int _currentIndex; - - protected override void Definition() - { - InputTrigger = ControlInput(nameof(InputTrigger), Process); - OutputTrigger = ControlOutput(nameof(OutputTrigger)); - - LightGroup = ValueInput(nameof(LightGroup), null); - - Value = ValueInput(nameof(Value), 0); - ColorChannel = ValueInput(nameof(ColorChannel), Engine.Math.ColorChannel.Alpha); - Step = ValueInput(nameof(Step), 1); - - Requirement(LightGroup, InputTrigger); - Requirement(Value, InputTrigger); - Succession(InputTrigger, OutputTrigger); - } - - private ControlOutput Process(Flow flow) - { - if (!AssertPlayer(flow)) { - Debug.LogError("Cannot find player."); - return OutputTrigger; - } - - var valueRaw = flow.GetValue(Value); - var colorChannelRaw = flow.GetValue(ColorChannel); - var stepRaw = flow.GetValue(Step); - var lamps = flow.GetValue(LightGroup).Lights; - - for (var index = 0; index < lamps.Count; index++) { - Player.Lamp(lamps[index]).OnLamp( - index >= _currentIndex * stepRaw && index < (_currentIndex + 1) * stepRaw ? valueRaw : 0, - colorChannelRaw); - } - - if (++_currentIndex >= lamps.Count / stepRaw) { - _currentIndex = 0; - } - - return OutputTrigger; - } - } -} +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Unity.VisualScripting; +using UnityEngine; + +namespace VisualPinball.Unity.VisualScripting +{ + [UnitTitle("Pulse Switch")] + [UnitSurtitle("Gamelogic Engine")] + [UnitCategory("Visual Pinball")] + public class PulseSwitchUnit : GleUnit, IMultiInputUnit + { + [DoNotSerialize] + [PortLabelHidden] + public ControlInput InputTrigger; + + [DoNotSerialize] + [PortLabelHidden] + public ControlOutput OutputTrigger; + + [SerializeAs(nameof(inputCount))] + private int _inputCount = 1; + + [DoNotSerialize] + [Inspectable, UnitHeaderInspectable("Switch IDs")] + public int inputCount + { + get => _inputCount; + set => _inputCount = Mathf.Clamp(value, 1, 10); + } + + [DoNotSerialize] + public ReadOnlyCollection multiInputs { get; private set; } + + [DoNotSerialize] + [PortLabel("Delay (ms)")] + public ValueInput PulseDelay { get; private set; } + + protected override void Definition() + { + InputTrigger = ControlInput(nameof(InputTrigger), Process); + OutputTrigger = ControlOutput(nameof(OutputTrigger)); + + var _multiInputs = new List(); + + multiInputs = _multiInputs.AsReadOnly(); + + for (var i = 0; i < inputCount; i++) { + var input = ValueInput(i.ToString(), string.Empty); + _multiInputs.Add(input); + + Requirement(input, InputTrigger); + } + + PulseDelay = ValueInput(nameof(PulseDelay), 250); + + Succession(InputTrigger, OutputTrigger); + } + + private ControlOutput Process(Flow flow) + { + if (!AssertGle(flow)) { + Debug.LogError("Cannot find GLE."); + return OutputTrigger; + } + + if (!AssertPlayer(flow)) { + Debug.LogError("Cannot find Player."); + return OutputTrigger; + } + + var pulseDuration = flow.GetValue(PulseDelay); + + foreach (var input in multiInputs) { + var switchId = flow.GetValue(input); + Gle.Switch(switchId, true); + Player.ScheduleAction(pulseDuration, () => Gle.Switch(switchId, false)); + } + + return OutputTrigger; + } + } +} diff --git a/Runtime/Nodes/Switches/PulseSwitchUnit.cs.meta b/Runtime/Nodes/Switches/PulseSwitchUnit.cs.meta new file mode 100644 index 0000000..1cff8fa --- /dev/null +++ b/Runtime/Nodes/Switches/PulseSwitchUnit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 87c039580d29b44b98a54b1ca747ba26 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/Lamps/SetLightUnit.cs b/Runtime/Nodes/Switches/SetSwitchUnit.cs similarity index 53% rename from Runtime/Nodes/Lamps/SetLightUnit.cs rename to Runtime/Nodes/Switches/SetSwitchUnit.cs index f899bc4..901f08e 100644 --- a/Runtime/Nodes/Lamps/SetLightUnit.cs +++ b/Runtime/Nodes/Switches/SetSwitchUnit.cs @@ -14,17 +14,17 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +using System.Collections.Generic; +using System.Collections.ObjectModel; using Unity.VisualScripting; using UnityEngine; -using VisualPinball.Engine.Math; namespace VisualPinball.Unity.VisualScripting { - [UnitTitle("Set Lamp (Component, Value, Channel)")] - [UnitShortTitle("Set Lamp")] - [UnitSurtitle("Scene")] + [UnitTitle("Set Switch")] + [UnitSurtitle("Gamelogic Engine")] [UnitCategory("Visual Pinball")] - public class SetLightUnit : GleUnit + public class SetSwitchUnit : GleUnit, IMultiInputUnit { [DoNotSerialize] [PortLabelHidden] @@ -34,49 +34,60 @@ public class SetLightUnit : GleUnit [PortLabelHidden] public ControlOutput OutputTrigger; + [SerializeAs(nameof(inputCount))] + private int _inputCount = 1; + [DoNotSerialize] - [PortLabel("Component")] - public ValueInput LampComponent; + [Inspectable, UnitHeaderInspectable("Switch IDs")] + public int inputCount + { + get => _inputCount; + set => _inputCount = Mathf.Clamp(value, 1, 10); + } [DoNotSerialize] - [PortLabel("Intensity")] - public ValueInput Value; + public ReadOnlyCollection multiInputs { get; private set; } [DoNotSerialize] - [PortLabel("Color Channel")] - public ValueInput ColorChannel; + [PortLabel("Value")] + public ValueInput IsEnabled { get; private set; } protected override void Definition() { InputTrigger = ControlInput(nameof(InputTrigger), Process); OutputTrigger = ControlOutput(nameof(OutputTrigger)); - LampComponent = ValueInput(nameof(LampComponent), null); + var _multiInputs = new List(); - Value = ValueInput(nameof(Value), 0f); - ColorChannel = ValueInput(nameof(ColorChannel), Engine.Math.ColorChannel.Alpha); + multiInputs = _multiInputs.AsReadOnly(); + + for (var i = 0; i < inputCount; i++) { + var input = ValueInput(i.ToString(), string.Empty); + _multiInputs.Add(input); + + Requirement(input, InputTrigger); + } + + IsEnabled = ValueInput(nameof(IsEnabled), false); - Requirement(LampComponent, InputTrigger); Succession(InputTrigger, OutputTrigger); } private ControlOutput Process(Flow flow) { - if (!AssertPlayer(flow)) { - Debug.LogError("Cannot find player."); + if (!AssertGle(flow)) { + Debug.LogError("Cannot find GLE."); return OutputTrigger; } - if (flow.GetValue(LampComponent) is ILampDeviceComponent lamp) { - var valueRaw = flow.GetValue(Value); - var colorChannelRaw = flow.GetValue(ColorChannel); + var isEnabled = flow.GetValue(IsEnabled); - Player.Lamp(lamp)?.OnLamp(valueRaw, colorChannelRaw); + foreach (var input in multiInputs) { + var switchId = flow.GetValue(input); + Gle.Switch(switchId, isEnabled); } return OutputTrigger; } - - } } diff --git a/Runtime/Nodes/Switches/SetSwitchUnit.cs.meta b/Runtime/Nodes/Switches/SetSwitchUnit.cs.meta new file mode 100644 index 0000000..e2e4677 --- /dev/null +++ b/Runtime/Nodes/Switches/SetSwitchUnit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e43245b55a5e94d4082380bedbe0bc42 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/Switches/SwitchEnabledEventUnit.cs b/Runtime/Nodes/Switches/SwitchEnabledEventUnit.cs new file mode 100644 index 0000000..f204534 --- /dev/null +++ b/Runtime/Nodes/Switches/SwitchEnabledEventUnit.cs @@ -0,0 +1,73 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Unity.VisualScripting; +using UnityEngine; + +namespace VisualPinball.Unity.VisualScripting +{ + [UnitTitle("On Switch Enabled")] + [UnitSurtitle("Gamelogic Engine")] + [UnitCategory("Events\\Visual Pinball")] + public class SwitchEnabledEventUnit : GleEventUnit, IMultiInputUnit + { + [SerializeAs(nameof(inputCount))] + private int _inputCount = 1; + + [DoNotSerialize] + [Inspectable, UnitHeaderInspectable("Switch IDs")] + public int inputCount + { + get => _inputCount; + set => _inputCount = Mathf.Clamp(value, 1, 10); + } + + [DoNotSerialize] + public ReadOnlyCollection multiInputs { get; private set; } + + [DoNotSerialize] + protected override bool register => true; + + // Adding an EventHook with the name of the event to the list of visual scripting events. + public override EventHook GetHook(GraphReference reference) => new EventHook(VisualScriptingEventNames.SwitchEvent); + + protected override void Definition() + { + base.Definition(); + + var _multiInputs = new List(); + + multiInputs = _multiInputs.AsReadOnly(); + + for (var i = 0; i < inputCount; i++) { + _multiInputs.Add(ValueInput(i.ToString(), string.Empty)); + } + } + + protected override bool ShouldTrigger(Flow flow, SwitchEventArgs2 args) + { + foreach(var input in multiInputs) { + if (flow.GetValue(input) == args.Id && args.IsEnabled) { + return true; + } + } + + return false; + } + } +} diff --git a/Runtime/Nodes/Switches/SwitchEnabledEventUnit.cs.meta b/Runtime/Nodes/Switches/SwitchEnabledEventUnit.cs.meta new file mode 100644 index 0000000..378e7a9 --- /dev/null +++ b/Runtime/Nodes/Switches/SwitchEnabledEventUnit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5a896594a52944a3e8f0c3f69e85d254 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Nodes/Switches/SwitchEventUnit.cs b/Runtime/Nodes/Switches/SwitchEventUnit.cs index c1696a7..aec13e2 100644 --- a/Runtime/Nodes/Switches/SwitchEventUnit.cs +++ b/Runtime/Nodes/Switches/SwitchEventUnit.cs @@ -14,18 +14,31 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +using System.Collections.Generic; +using System.Collections.ObjectModel; using Unity.VisualScripting; +using UnityEngine; namespace VisualPinball.Unity.VisualScripting { [UnitTitle("On Switch Changed")] [UnitSurtitle("Gamelogic Engine")] [UnitCategory("Events\\Visual Pinball")] - public class SwitchEventUnit : GleEventUnit + public class SwitchEventUnit : GleEventUnit, IMultiInputUnit { + [SerializeAs(nameof(inputCount))] + private int _inputCount = 1; + + [DoNotSerialize] + [Inspectable, UnitHeaderInspectable("Switch IDs")] + public int inputCount + { + get => _inputCount; + set => _inputCount = Mathf.Clamp(value, 1, 10); + } + [DoNotSerialize] - [PortLabel("Switch ID")] - public ValueInput Id { get; private set; } + public ReadOnlyCollection multiInputs { get; private set; } [DoNotSerialize] [PortLabel("Is Enabled")] @@ -43,13 +56,26 @@ protected override void Definition() { base.Definition(); - Id = ValueInput(nameof(Id), string.Empty); + var _multiInputs = new List(); + + multiInputs = _multiInputs.AsReadOnly(); + + for (var i = 0; i < inputCount; i++) { + _multiInputs.Add(ValueInput(i.ToString(), string.Empty)); + } + IsEnabled = ValueOutput(nameof(IsEnabled)); } protected override bool ShouldTrigger(Flow flow, SwitchEventArgs2 args) { - return flow.GetValue(Id) == args.Id; + foreach (var input in multiInputs) { + if (flow.GetValue(input) == args.Id) { + return true; + } + } + + return false; } protected override void AssignArguments(Flow flow, SwitchEventArgs2 args) diff --git a/package.json b/package.json index 7b18c80..33ef1f6 100644 --- a/package.json +++ b/package.json @@ -10,9 +10,9 @@ "Visual" ], "unity": "2021.2", - "unityRelease": "8f1", + "unityRelease": "11f1", "dependencies": { - "com.unity.visualscripting": "1.7.6", + "com.unity.visualscripting": "1.7.7", "org.visualpinball.engine.unity": "0.0.1-preview.90" }, "author": "freezy ",