1414// You should have received a copy of the GNU General Public License
1515// along with this program. If not, see <https://www.gnu.org/licenses/>.
1616
17+ using System ;
1718using System . Collections . Generic ;
1819using System . Collections . ObjectModel ;
20+ using System . Linq ;
1921using Unity . VisualScripting ;
2022using UnityEngine ;
23+ using VisualPinball . Engine . Game . Engines ;
24+ using Color = VisualPinball . Engine . Math . Color ;
2125
2226namespace VisualPinball . Unity . VisualScripting
2327{
28+ public struct LightComponentMapping
29+ {
30+ public LightComponent lightComponent ;
31+ public string id ;
32+
33+ public bool IsValid ( ) => ! lightComponent . IsUnityNull ( ) ;
34+ }
35+
2436 [ UnitTitle ( "Lamp Sequence" ) ]
2537 [ UnitSurtitle ( "Gamelogic Engine" ) ]
2638 [ UnitCategory ( "Visual Pinball" ) ]
2739 public class LampSequenceUnit : GleUnit , IMultiInputUnit
2840 {
41+ [ Serialize , Inspectable , UnitHeaderInspectable ( "Value" ) ]
42+ public LampDataType ValueDataType { get ; set ; }
43+
44+ [ Serialize , Inspectable , UnitHeaderInspectable ( "Non Step Value" ) ]
45+ public LampDataType NonStepValueDataType { get ; set ; }
46+
47+ [ DoNotSerialize ]
48+ [ Inspectable , UnitHeaderInspectable ( "Lamp IDs" ) ]
49+ public int inputCount
50+ {
51+ get => _inputCount ;
52+ set => _inputCount = Mathf . Clamp ( value , 1 , 10 ) ;
53+ }
54+
2955 [ DoNotSerialize ]
3056 [ PortLabelHidden ]
3157 public ControlInput InputTrigger ;
@@ -38,55 +64,66 @@ public class LampSequenceUnit : GleUnit, IMultiInputUnit
3864 private int _inputCount = 1 ;
3965
4066 [ DoNotSerialize ]
41- [ Inspectable , UnitHeaderInspectable ( "Lamp IDs" ) ]
42- public int inputCount
43- {
44- get => _inputCount ;
45- set => _inputCount = Mathf . Clamp ( value , 1 , 10 ) ;
46- }
67+ public ReadOnlyCollection < ValueInput > multiInputs { get ; private set ; }
4768
4869 [ DoNotSerialize ]
49- public ReadOnlyCollection < ValueInput > multiInputs { get ; private set ; }
70+ [ PortLabel ( "Step" ) ]
71+ public ValueInput Step ;
5072
5173 [ DoNotSerialize ]
52- [ PortLabel ( "Value" ) ]
5374 public ValueInput Value { get ; private set ; }
5475
5576 [ DoNotSerialize ]
56- [ PortLabel ( "Step" ) ]
57- public ValueInput Step ;
77+ public ValueInput NonStepValue { get ; private set ; }
78+
79+ [ DoNotSerialize ]
80+ private readonly Dictionary < string , float > _intensityMultipliers = new ( ) ;
5881
82+ private List < LightComponentMapping > _lightComponentCache = new ( ) ;
5983 private int _currentIndex ;
60- private List < LightComponent > _lightComponentCache = null ;
6184
6285 protected override void Definition ( )
6386 {
6487 InputTrigger = ControlInput ( nameof ( InputTrigger ) , Process ) ;
6588 OutputTrigger = ControlOutput ( nameof ( OutputTrigger ) ) ;
6689
67- var _multiInputs = new List < ValueInput > ( ) ;
68-
69- multiInputs = _multiInputs . AsReadOnly ( ) ;
90+ var mi = new List < ValueInput > ( ) ;
91+ multiInputs = mi . AsReadOnly ( ) ;
7092
7193 for ( var i = 0 ; i < inputCount ; i ++ ) {
7294 var input = ValueInput ( i . ToString ( ) , string . Empty ) ;
73- _multiInputs . Add ( input ) ;
74-
95+ mi . Add ( input ) ;
7596 Requirement ( input , InputTrigger ) ;
7697 }
7798
78- Value = ValueInput ( nameof ( Value ) , 0f ) ;
7999 Step = ValueInput ( nameof ( Step ) , 1 ) ;
80100
101+ Value = ValueDataType switch
102+ {
103+ LampDataType . OnOff => ValueInput ( nameof ( Value ) , false ) ,
104+ LampDataType . Status => ValueInput ( nameof ( Value ) , LampStatus . Off ) ,
105+ LampDataType . Intensity => ValueInput ( nameof ( Value ) , 0f ) ,
106+ LampDataType . Color => ValueInput ( nameof ( Value ) , UnityEngine . Color . white ) ,
107+ _ => throw new ArgumentOutOfRangeException ( )
108+ } ;
109+
110+ NonStepValue = NonStepValueDataType switch
111+ {
112+ LampDataType . OnOff => ValueInput ( nameof ( NonStepValue ) , false ) ,
113+ LampDataType . Status => ValueInput ( nameof ( NonStepValue ) , LampStatus . Off ) ,
114+ LampDataType . Intensity => ValueInput ( nameof ( NonStepValue ) , 0f ) ,
115+ LampDataType . Color => ValueInput ( nameof ( NonStepValue ) , UnityEngine . Color . white ) ,
116+ _ => throw new ArgumentOutOfRangeException ( )
117+ } ;
118+
81119 Succession ( InputTrigger , OutputTrigger ) ;
82120
83- _lightComponentCache = null ;
121+ _lightComponentCache . Clear ( ) ;
84122 }
85123
86124 private ControlOutput Process ( Flow flow )
87125 {
88- if ( ! AssertGle ( flow ) )
89- {
126+ if ( ! AssertGle ( flow ) ) {
90127 Debug . LogError ( "Cannot find GLE." ) ;
91128 return OutputTrigger ;
92129 }
@@ -96,52 +133,99 @@ private ControlOutput Process(Flow flow)
96133 return OutputTrigger ;
97134 }
98135
99- var value = flow . GetValue < float > ( Value ) ;
100- var stepRaw = flow . GetValue < int > ( Step ) ;
101-
102- if ( _lightComponentCache != null ) {
103- foreach ( var component in _lightComponentCache ) {
104- if ( component . IsUnityNull ( ) ) {
105- _lightComponentCache = null ;
106- break ;
107- }
136+ foreach ( var mapping in _lightComponentCache ) {
137+ if ( ! mapping . IsValid ( ) ) {
138+ _lightComponentCache . Clear ( ) ;
139+ break ;
108140 }
109141 }
110142
111- if ( _lightComponentCache == null ) {
112- _lightComponentCache = new List < LightComponent > ( ) ;
113-
143+ if ( _lightComponentCache . Count == 0 ) {
114144 foreach ( var input in multiInputs ) {
115145 var lampId = flow . GetValue < string > ( input ) ;
116- _lightComponentCache . AddRange ( Flatten ( Player . LampDevice ( lampId ) ) ) ;
146+
147+ var mapping = Player . LampMapping . FirstOrDefault ( l => l . Id == lampId ) ;
148+ if ( mapping != null ) {
149+ UpdateLightComponentCache ( mapping . Device , lampId ) ;
150+ }
151+ else {
152+ Debug . LogError ( $ "Unknown lamp ID { lampId } .") ;
153+ _lightComponentCache . Clear ( ) ;
154+
155+ break ;
156+ }
117157 }
118158 }
119159
160+ var stepRaw = flow . GetValue < int > ( Step ) ;
161+
162+ LampDataType dataType ;
163+ ValueInput value ;
164+
120165 for ( var index = 0 ; index < _lightComponentCache . Count ; index ++ ) {
121- ;
166+ if ( index >= _currentIndex * stepRaw && index < ( _currentIndex + 1 ) * stepRaw ) {
167+ dataType = ValueDataType ;
168+ value = Value ;
169+ }
170+ else {
171+ dataType = NonStepValueDataType ;
172+ value = NonStepValue ;
173+ }
174+
175+ var lampApi = Player . Lamp ( _lightComponentCache [ index ] . lightComponent ) ;
176+
177+ switch ( dataType ) {
178+ case LampDataType . OnOff :
179+ lampApi . OnLamp ( flow . GetValue < bool > ( value ) ? LampStatus . On : LampStatus . Off ) ;
180+ break ;
181+ case LampDataType . Status :
182+ lampApi . OnLamp ( flow . GetValue < LampStatus > ( value ) ) ;
183+ break ;
184+ case LampDataType . Intensity :
185+ lampApi . OnLamp ( flow . GetValue < float > ( value ) * GetIntensityMultiplier ( _lightComponentCache [ index ] . id ) ) ;
186+ break ;
187+ case LampDataType . Color :
188+ lampApi . OnLamp ( flow . GetValue < UnityEngine . Color > ( value ) ) ;
189+ break ;
190+ default :
191+ throw new ArgumentOutOfRangeException ( ) ;
192+ }
122193 }
123194
124195 if ( ++ _currentIndex >= _lightComponentCache . Count / stepRaw ) {
125196 _currentIndex = 0 ;
126197 }
127-
198+
128199 return OutputTrigger ;
129200 }
130201
131- private List < LightComponent > Flatten ( List < ILampDeviceComponent > lampDeviceList )
202+ private float GetIntensityMultiplier ( string id )
132203 {
133- List < LightComponent > lights = new List < LightComponent > ( ) ;
204+ if ( _intensityMultipliers . ContainsKey ( id ) ) {
205+ return _intensityMultipliers [ id ] ;
206+ }
134207
135- foreach ( ILampDeviceComponent device in lampDeviceList ) {
136- if ( device is LightComponent ) {
137- lights . Add ( device as LightComponent ) ;
138- }
139- else if ( device is LightGroupComponent ) {
140- lights . AddRange ( Flatten ( ( ( LightGroupComponent ) device ) . Lights ) ) ;
141- }
208+ var mapping = Player . LampMapping . FirstOrDefault ( l => l . Id == id ) ;
209+ if ( mapping == null ) {
210+ Debug . LogError ( $ "Unknown lamp ID { id } .") ;
211+ _intensityMultipliers [ id ] = 1 ;
212+ return 1 ;
142213 }
143214
144- return lights ;
215+ _intensityMultipliers [ id ] = mapping . Type == LampType . Rgb ? 255 : 1 ;
216+ return _intensityMultipliers [ id ] ;
217+ }
218+
219+ private void UpdateLightComponentCache ( ILampDeviceComponent device , string id )
220+ {
221+ if ( device is LightComponent ) {
222+ _lightComponentCache . Add ( new LightComponentMapping { lightComponent = device as LightComponent , id = id } ) ;
223+ }
224+ else if ( device is LightGroupComponent ) {
225+ foreach ( var light in ( device as LightGroupComponent ) . Lights ) {
226+ UpdateLightComponentCache ( light , id ) ;
227+ }
228+ }
145229 }
146230 }
147231}
0 commit comments