@@ -39,9 +39,10 @@ namespace VisualPinball.Engine.PinMAME
3939 [ DisallowMultipleComponent ]
4040 [ RequireComponent ( typeof ( AudioSource ) ) ]
4141 [ AddComponentMenu ( "Pinball/Gamelogic Engine/PinMAME" ) ]
42- public class PinMameGamelogicEngine : MonoBehaviour , IGamelogicEngine
42+ public class PinMameGamelogicEngine : MonoBehaviour , IGamelogicEngine , IGamelogicInputThreading
4343 {
4444 public string Name { get ; } = "PinMAME Gamelogic Engine" ;
45+ public GamelogicInputDispatchMode SwitchDispatchMode => GamelogicInputDispatchMode . SimulationThread ;
4546
4647 public const string DmdPrefix = "dmd" ;
4748 public const string SegDispPrefix = "display" ;
@@ -148,8 +149,9 @@ public GamelogicEngineLamp[] RequestedLamps {
148149
149150 public bool _solenoidsEnabled ;
150151 public long _solenoidDelayStart ;
151- private Dictionary < int , PinMameMechComponent > _registeredMechs = new ( ) ;
152- private HashSet < int > _mechSwitches = new ( ) ;
152+ private Dictionary < int , PinMameMechComponent > _registeredMechs = new ( ) ;
153+ private Dictionary < int , string > _registeredMechNames = new ( ) ;
154+ private HashSet < int > _mechSwitches = new ( ) ;
153155
154156 private bool _toggleSpeed = false ;
155157 private Keyboard _keyboard ;
@@ -186,10 +188,16 @@ private void Update()
186188 }
187189
188190 lock ( _dispatchQueue ) {
189- while ( _dispatchQueue . Count > 0 ) {
190- _dispatchQueue . Dequeue ( ) . Invoke ( ) ;
191- }
192- }
191+ while ( _dispatchQueue . Count > 0 ) {
192+ var callback = _dispatchQueue . Dequeue ( ) ;
193+ try {
194+ callback . Invoke ( ) ;
195+ }
196+ catch ( Exception e ) {
197+ Logger . Error ( e , "[PinMAME] Exception while processing main-thread dispatch callback." ) ;
198+ }
199+ }
200+ }
193201
194202 // lamps
195203 _pinMame . GetChangedLamps ( _changedLamps ) ;
@@ -922,13 +930,13 @@ private void OnSolenoidUpdated(int id, bool isActive)
922930
923931 var coil = _coils [ _pinMameIdToCoilIdMapping [ id ] ] ;
924932
925- if ( _solenoidsEnabled ) {
926- Logger . Info ( $ "[PinMAME] <= coil { coil . Id } : { isActive } | { coil . Description } ") ;
927-
928- lock ( _dispatchQueue ) {
929- _dispatchQueue . Enqueue ( ( ) => OnCoilChanged ? . Invoke ( this , new CoilEventArgs ( coil . Id , isActive ) ) ) ;
930- }
931- }
933+ if ( _solenoidsEnabled ) {
934+ Logger . Info ( $ "[PinMAME] <= coil { coil . Id } : { isActive } | { coil . Description } ") ;
935+
936+ lock ( _dispatchQueue ) {
937+ _dispatchQueue . Enqueue ( ( ) => OnCoilChanged ? . Invoke ( this , new CoilEventArgs ( coil . Id , isActive ) ) ) ;
938+ }
939+ }
932940 else {
933941 Logger . Info ( $ "[PinMAME] <= solenoids disabled, coil { coil . Id } : { isActive } | { coil . Description } ") ;
934942 }
@@ -1011,11 +1019,13 @@ public bool GetSwitch(string id)
10111019
10121020 #region Mechs
10131021
1014- public void RegisterMech ( PinMameMechComponent mechComponent )
1015- {
1016- var id = _numMechs ++ ;
1017- _registeredMechs [ id ] = mechComponent ;
1018- }
1022+ public void RegisterMech ( PinMameMechComponent mechComponent )
1023+ {
1024+ // PinMAME mech numbers are 1-based.
1025+ var id = ++ _numMechs ;
1026+ _registeredMechs [ id ] = mechComponent ;
1027+ _registeredMechNames [ id ] = mechComponent ? mechComponent . name : "<null-mech>" ;
1028+ }
10191029
10201030 private void OnMechAvailable ( int mechNo , PinMameMechInfo mechInfo )
10211031 {
@@ -1034,21 +1044,25 @@ private void OnMechUpdated(int mechNo, PinMameMechInfo mechInfo)
10341044 }
10351045 }
10361046
1037- private void SendMechs ( )
1038- {
1039- var max = _pinMame . GetMaxMechs ( ) ;
1040- foreach ( var ( id , mech ) in _registeredMechs ) {
1041- if ( id > max ) {
1042- Logger . Error ( $ "PinMAME only supports up to { max } custom mechs, ignoring { mech . name } .") ;
1043- return ;
1044- }
1045- var mechConfig = mech . Config ( _player . SwitchMapping , _player . CoilMapping , _switchIdToPinMameIdMappings , _coilIdToPinMameIdMapping ) ;
1046- _pinMame . SetMech ( id , mechConfig ) ;
1047- foreach ( var c in mechConfig . SwitchList ) {
1048- _mechSwitches . Add ( c . SwNo ) ;
1049- }
1050- }
1051- }
1047+ private void SendMechs ( )
1048+ {
1049+ var max = _pinMame . GetMaxMechs ( ) ;
1050+ Logger . Info ( $ "[PinMAME] Registering { _registeredMechs . Count } mech(s). PinMAME reports max mech slots={ max } .") ;
1051+ foreach ( var ( id , mech ) in _registeredMechs ) {
1052+ var mechName = _registeredMechNames . TryGetValue ( id , out var name ) ? name : $ "mech#{ id } ";
1053+ // GetMaxMechs() returns the count of available slots and valid mech numbers are 1..max.
1054+ if ( id > max ) {
1055+ Logger . Error ( $ "PinMAME supports { max } custom mech slot(s). Cannot register mech id={ id } ({ mechName } ).") ;
1056+ continue ;
1057+ }
1058+ var mechConfig = mech . Config ( _player . SwitchMapping , _player . CoilMapping , _switchIdToPinMameIdMappings , _coilIdToPinMameIdMapping ) ;
1059+ Logger . Info ( $ "[PinMAME] Registering mech id={ id } , name={ mechName } , switches={ mechConfig . SwitchList . Count } .") ;
1060+ _pinMame . SetMech ( id , mechConfig ) ;
1061+ foreach ( var c in mechConfig . SwitchList ) {
1062+ _mechSwitches . Add ( c . SwNo ) ;
1063+ }
1064+ }
1065+ }
10521066
10531067 #endregion
10541068
0 commit comments