@@ -69,6 +69,106 @@ git update-index --assume-unchanged Plugins/VisualPinball.Engine.Mpf.dll.meta
69
69
git update-index --assume-unchanged Plugins/VisualPinball.Engine.Mpf.pdb.meta
70
70
```
71
71
72
+ ## Design
73
+
74
+ MPF is a standalone Python application and not a library. Despite this, we want
75
+ to make its use with VPE as seamless as possible, so we include precompiled MPF
76
+ binaries and start them together with VPE automatically. The process of starting
77
+ up and communicating with MPF via gRPC while respecting the many configuration
78
+ options that are available is quite complex and managed in a single class:
79
+ ` MpfWrangler ` . It could be worthwhile to split it up into one class that manages
80
+ the MPF process and another that manages the gRPC connection.
81
+
82
+ MPF has two APIs: One to control hardware on the playfield, and one to play
83
+ media in the backbox. The former is the main, essential part of this MPF
84
+ integration and the latter was added later. The hardware controller is
85
+ responsible for sending switch changes to MPF and applying its commands to
86
+ correct items on the playfield. This is done by the class ` MpfGamelogicEngine ` .
87
+ It also retrieves and stores the machine description from MPF at design time,
88
+ which allows the table author to create the mapping between MPF and VPE coils,
89
+ lamps and switches that is used at runtime to control the playfield.
90
+
91
+ ### MPF Binaries
92
+
93
+ The precompiled binaries included here are slightly different from the official
94
+ version of MPF. They are based on ` 0.80.0.dev6 ` , with the addition of a _ Ping_
95
+ RPC that allows VPE to check whether MPF is ready without any side effects (like
96
+ starting the game). This way, the game can start as soon as MPF is ready,
97
+ regardless of how long MPF takes to start up. I have
98
+ [ proposed this change] ( https://github.com/missionpinball/mpf/pull/1865 ) to the
99
+ MPF developers, but as of February 2025 they have not yet gotten around to
100
+ including it in the official version. The binaries were made using
101
+ [ PyInstaller] ( https://pyinstaller.org ) . I'm not completely sure anymore what
102
+ parameters I used, but this should be pretty close:
103
+ ` pyinstaller --collect-all mpf --exclude-module mpf.tests --name mpf --noconfirm mpf/**main**.py ` .
104
+
105
+ ### Media controller
106
+
107
+ This repository includes a basic media controller implementation that is fully
108
+ compliant with the
109
+ [ BCP spec] ( https://missionpinball.org/latest/code/BCP_Protocol/ ) and can parse
110
+ all documented message types. Without writing code, table authors can trigger
111
+ sounds, toggle game objects and display variables in text fields, but its
112
+ capabilities are not comparable to those of the official Kivvy and Godot based
113
+ media controllers made by the MPF developers.
114
+
115
+ #### Connection
116
+
117
+ When the included media controller is selected in the game logic engine
118
+ inspector, the ` MpfWrangler ` creates the ` BcpInterface ` in its constructor,
119
+ which in turn creates the ` BcpServer ` that ultimately starts a ` TcpListener ` to
120
+ send and receive messages from MPF via TCP. Messages are sent and received
121
+ through a message queue, but the server does not run on a separate thread.
122
+
123
+ #### Parsing
124
+
125
+ To communicate with the various available media controller implementations, the
126
+ MPF developers invented their own little message format called
127
+ '[ Backbox Control Protocol] ( https://missionpinball.org/latest/code/BCP_Protocol/ ) ,'
128
+ or BCP for short. The downside compared to something like gRPC is that there is
129
+ no parser. All we get is strings. Much of the code that comprises VPE's media
130
+ controller is dedicated to parsing those message strings into strongly typed C#
131
+ objects and back. For each message type, there is a class that parses and
132
+ represents instances of it.
133
+
134
+ #### Reacting to messages
135
+
136
+ There is also a message handler class for each type of message that fires an
137
+ event every time a message of the associated type is received. Some message
138
+ types must be requested by the media controller using the
139
+ [ ` monitor_start ` ] ( https://missionpinball.org/latest/code/BCP_Protocol/monitor_start/ )
140
+ command. By the number of listeners to the events of each message handler, we
141
+ can tell when a message type is actually of interest and monitor only those
142
+ message types.
143
+
144
+ #### Monitoring
145
+
146
+ Many BCP message types are sent when some variable in MPF changes. For easy
147
+ access to these values in VPE, there are monitoring classes for these types of
148
+ messages that share a common base class and provide the most recently sent value
149
+ and an event that is triggered when a new value is received. For example, using
150
+ the ` CurrentPlayerPlayerMonitor ` class, other code can easily keep track of
151
+ whose turn it is without having to go through the
152
+ ` PlayerTurnStartMessageHandler ` .
153
+
154
+ #### Limitations
155
+
156
+ To the table author, who is not really allowed to write C# code because it
157
+ cannot be shipped with the table file, we offer a few Unity components that can
158
+ make sounds and toggle objects based on events and modes from MPF and display
159
+ player and machine variables in text fields. The sad part is that this severely
160
+ limits what would otherwise be possible with this media controller
161
+ implementation. Many message types are not accessible and some fairly basic
162
+ functionality like displaying player variables of a player other than the
163
+ currently active one is not supported. To fix this, the selection of components
164
+ and their feature-set should grow and there should be a visual scripting
165
+ interface for less common use-cases.
166
+
167
+ The most important missing feature is support for slides or more generally
168
+ support for displaying stuff on the backbox display. The first obstacle here is
169
+ that the way slides work in MPF is
170
+ [ not officially defined or documented] ( https://github.com/missionpinball/mpf-gmc/issues/26 ) .
171
+
72
172
## License
73
173
74
174
[ MIT] ( LICENSE )
0 commit comments