|
P3-SDK 0.9
P3 Software Development Kit
|
Upper playfield modules contain all of the playfield features beyond the row of scoops on the P3 playfield and in some cases additional features that mount elsewhere, such as over the lower playfield or on top of the bbackbox (eg. a topper). New game developers can optionally develop new upper playfield modules for their game, or they can write their game to work with one or more existing playfield modules. Creating a new playfield module involves both creating the physical module and also creating a "module driver" so software running on the P3 knows how to interface to the playfield module's features.
Multimorphic publishes mechanical specifications and some CAD files useful for creating the physical playfield module.
This includes:
To access the hardware specifications, first create an account on the Multimorphic's Account Page. Then click over to the Support page -> Maintenance, troubleshooting, technical manuals, how-to videos, tutorials, etc. -> 3rd-Party Development Kit.
For more details on the mechanicals, please contact support@multimorphic.com
In order to communicate with the rest of the P3 system, playfield modules generally need SW-16 switch boards that keep track of the states of every switch on the playfield, and they need PD-16 and/or PD-LED driver boards to control coils/DC-motors/magnets and LED/Servos/Steppers, respectively.
For more details on the electronics, please contact support@multimorphic.com
Every upper playfield module design has a unique identifier (string) that is read by the P3 at startup. This identifier is assigned by Multimorphic. To request an identifier for a new module, contact support@multimorphic.com. That identifier will then be used in a number of places to help inform the P3 when a specific module is installed and to tell the P3 what files to load to understand how an app can interact with the module.
To identify itself to the P3 machine when installed, playfield modules need a USB storage device with specific contents, including an identification certificate provided by Multimorphic. Please contact support@multimorphic.com for more information about the USB device.
A playfield module driver includes a number of files that allow apps on the P3 to interact with features on the playfield module. It is installed in the ~/.multimorphic/P3/ModuleDrivers/<module_identifier>/<module_driver_version>/ folder. When installing a module driver package on the P3, System Manager will ensure the files are installed in the right place. For simulating on a development machine, the module driver files should be installed in the ~/.multimorphic/P3/ModuleDrivers/<module_identifier>/<module_driver_version>/ folder.
On Windows development machines, ~/ refers to "%HOMEDRIVE%%HOMEPATH%". To find the .multimorphic directory on a Windows machine, open up a command line and type cd /d "%HOMEDRIVE%%HOMEPATH%". When writing your game app, you simply define the ModuleID field in AppConfig.json, and the framework will handle the rest, loading the appropriate hardware configuration file, if it finds a matching module driver.
The files a module developer should create and include in the module driver are:
A playfield module definition file is what tells an app some specific details of features on the playfield. These details are required to be written in the JSON format, with specific fields as described below:
Available Sections:
| Section | Description |
|---|---|
| Game | Global parameters for the game |
| Flippers | One entry for each device that is automatically driven by the hardware when the flipper buttons are hit |
| Bumpers | One entry for each device that is automatically driven by the hardware when the corresponding switch is hit |
| UpperDisplay | Information on the presence and resolution of the mini-display on the playfield module |
| TroughLaunchers | Information required by game applications to configure trough-based ball launchers. |
| Switches | One entry for each switch |
| Coils | One entry for each coil |
| LEDs | One entry for each LED |
| LEDStrings | One entry for each WS2812-compatible string of LEDs |
| Servos | One entry for each servo motor |
| Steppers | One entry for each stepper motor |
| BallPaths | One entry for each playfield-specific shot and target |
Some fields specify a position on the playfield as an array of 3 floats [x, y, z]. The coordinate system is measured in inches, where [0,0,0] is the front left corner of the playfield module at the surface of the playfield. Positive x increases towards the right of the machine. Positive y increases towards the back of the machine. Positive z increases upwards from the playing surface. This means positions over the playfield screen use negative y coordinates.
Example:
This section describes a few global parameters:
| Field | Type | Description |
|---|---|---|
| Name | string | Name of the playfield module |
| machineType | string | Must be "PDB" |
| numBalls | int | Minimum number of balls that must be installed for normal operation of apps on this module. This is informative and not strictly enforced. Installing more balls is possible. Some apps may try to compensate if fewer balls are installed, but that normally results in a degraded experience. |
Example:
This section describes each flipper that is part of the playfield module design. Flippers are devices that are automatically driven by the hardware when the flipper buttons are hit.
Playfield module definition files should contain descriptions of flippers on the module itself plus the upper flippers (right above the side targets) that are safe and/or intended to be used with the module. Playfield module definition files must not contain descriptions of the lower main flippers, nor upper flippers that must remain disabled by design.
The Flipper definitions include the following fields:
| Field | Type | Description |
|---|---|---|
| Name | string | Name of the flipper |
| SettingsPrefix | string | Prefix for the GameAttributes associated with the flipper. These GameAttributes appear under "Service Menu/Settings/Mechs/Coils". |
| SwitchName | string | Switch name for the button used for primary activation. |
| SecondarySwitchName | string | Switch name for the button that should activate the flipper when one-handed play is enabled. |
| AlternateSwitchName | string | Switch name for the button that should activate the flipper when the 'activate all flippers with red buttons' operator setting is active. |
| EOSSwitchName | string | Name of the End Of Stroke Switch. Field is absent if no EOS Switch. |
| MainCoilName | string | Name of the Coil that provides the initial stroke. |
| HoldCoilName | string | Name of the Coil that keeps the flipper up. |
| Tags | string | Comma-separated list of tags the software can optionally use. |
Example:
Note - The upper flipper coils (auxRight0, auxRight1, auxLeft0, auxLeft1) are part of the base machine definition; they must not be defined in the Playfield Module Definition File.
This section describes each bumper. Playfield module definition files should only contain descriptions of bumpers that are part of the playfield module design. Bumpers are all devices for which the device's coil should be pulsed immediately following the activation of the device's switch. These typically include slingshots and pop bumpers.
The Bumper definitions include the following fields:
| Field | Type | Description |
|---|---|---|
| Name | string | Name of the bumper |
| SwitchName | string | Name of the Switch that activates the bumper |
| CoilName | string | Name of the Coil to be pulsed when the bumper activates |
| SettingName | string | Name of strength setting for the bumper. The setting can be shared with other pop bumpers or independent. |
| SwitchPolarity | bool | Polarity of the switch. Use true for NO switches, false for NC. Using the correct polarity will ensure the associated coil activates as quickly as possible when the ball hits the bumper. |
| AllowShotgunning | bool | If true, the coil will fire on every switch event. If false, the coil won't fire a second time due to switch events happening within the next 64ms. |
| Tags | string | Comma-separated list of tags the software can optionally use. |
Example:
This section describes the mini-display on the playfield module, when applicable. For example, Lexy Lightspeed - Escape From Earth and Cannon Lagoon have a mini-display, but Heist does not.
The UpperDisplay section includes the following fields:
| Field | Type | Description |
|---|---|---|
| Present | bool | true when the module has a mini-display, false otherwise |
| Width | int | Horizontal resolution of the mini-display, when applicable |
| Height | int | Vertical resolution of the mini-display, when applicable |
Example 1:
Example 2:
This section describes each TroughLauncher, which is a mechanism used to launch a ball from the P3's trough out to the playfield. The mechanisms usually just include a tube that mates with the P3's trough and one or two switches. Tubes are available from Multimorphic for each available trough launch position, and they can be ordered with or without switches. They can also be ordered with a ball-stopper, which keeps balls from rolling past that launch position in the trough. The leftmost tube installed on a playfield should contain the ball-stopper.
The TroughLauncher definitions include the following fields:
| Field | Type | Description |
|---|---|---|
| Name | string | Name of the launcher (not used by any code) |
| VUKNumber | int | Trough position for the launcher. There are 8 physical positions from left to right (0-7). 4 is the center one. There is no available launcher on the right end of the playfield. See the note below for launchers >= 8. |
| HighSwitch | string | Name of the higher of two possible switches. Required for all TroughLaunchers. For tubes used only for launching (Bidirectional=false), this switch is usually installed after the make point on the ball delivery system so that a switch event means a ball successfully exited the tube. The make point is the point at which the ball can no longer fall back into the tube. |
| LowSwitch | string | Name of the lower of the two possible switches. Required for Bidirectional=true TroughLaunchers. Not used for Bidirectional=false TroughLaunchers. In Bidirectional configurations, the software uses the LowSwitch to determine when a ball is going up the tube and when a ball is coming down the tube. |
| Bidirectional | bool | true for bidirectional operation (requires both HighSwitch and LowSwitch definitions). false for unidirectional operation (requires HighSwitch only). |
| CustomCode | bool | true for complex launching mechanisms that require custom code to get the ball into play (eg. multi-stage launchers or launchers with diverters). |
| Destination | string | Identifies the destination of the ball launch. See the available values below. |
| EntrancePosition | float[] | Geographic coordinate of the hole entrance, in inches: [x, y, z]. For bidirectional TroughLaunchers only. |
| ExitPosition | float[] | Geographic coordinate where the ball enters the playfield, in inches: [x, y, z]. This could be right above the TroughLauncher (like in CL) or at an inlane (like in LL-EE). |
| Tags | string | Comma-separated list of tags the software can optionally use. |
Example:
The TroughLauncher Destination field is used by apps that don't know specific details about the playfield (like apps written to work with any playfield module) to be able to request launches to useful destinations. Options include:
| Destination | Description |
|---|---|
| "LeftInlane" | Feeds the wireform going to the left inlane. |
| "RightInlane" | Feeds the wireform going to the right inlane. |
| "LowerPlayfield" | Ejected balls will find their way to the lower playfield, even if walls/scoops are raised. |
| "UpperPlayfield" | Ejected balls would get stuck behind any walls/scoops that are raised. |
| "StagingArea" | Ejected balls go into another position that isn't in-play on the playfield. |
These options are defined in Multimorphic.P3.Mechs.LaunchDestination
Note - it is possible to define multiple TroughLaunchers for the same tube for cases where a launch tube feeds a diverter or something else that can alter the movement of the ball. To do this, add 8 to the VUKNumber for each additional definition. TroughLaunchers that share the same tube must have identical values for the HighSwitch, LowSwitch, and Bidirectional fields. Balls detected as coming down a bidirectional tube will always get detected as coming down the actual/physical tube number (0-7).
Example:
This section describes each switch on the playfield module. Switches are wired to Multimorphic switch boards (available from Multimorphic). The first board must be set to address 4. Additional switch boards can be added, with addresses > 4. Each address corresponds to 16 switches. Therefore, the switch connected to the first input on address 4 is assigned number (16 * 4) = 64.
The Switch definitions include the following fields:
| Field | Type | Description |
|---|---|---|
| Name | string | Name of the switch. This is the name software will use to read the switch. |
| Type | string | "NC" for normally closed switches (switches that pull the switch board input to ground by default. "NO" for normally open switches. |
| Number | string | Value of 16*board address + board input number, converted to string. |
| Label | string | User-friendly string for displaying the switch name on graphics. |
| DebounceRequired | bool | false turns off debouncing, saving 1-2ms. Generally optos do not need debouncing, but that depends on the scenario. Default is true. |
| Tags | string | Comma-separated list of tags the software can optionally use. |
| Location | float[] | Geographic coordinate of the switch, in inches: [x, y, z]. |
Example:
This section describes each coil on the playfield module. Coils are wired to Multimorphic driver boards (available from Multimorphic). The first board must be set to address 6. Any number of additional driver boards can be added, with board addresses > 6. Each address corresponds to 16 coils (or other devices), configured as two banks of 8 (bank 0 and bank 1).
The Coil definitions include the following fields:
| Field | Type | Description |
|---|---|---|
| Name | string | Name of the coil. This is the name software will use to drive the coil. |
| Number | string | This is a formatted string Ax-By-z, where x is the board address, y is the bank number, and z is the output number. |
| Label | string | User-friendly string for displaying the coil name on graphics. |
| PulseTime | int | Default pulse length in milliseconds. Software can override this. |
| Tags | string | Comma-separated list of tags the software can optionally use. |
Example:
This section describes each LED on the playfield module. LEDs are wired to Multimorphic PD-LED boards (available from Multimorphic). The first board must be set to address 9. Any number of additional PD-LED boards can be added, with board addresses > 9. Each address corresponds to 84 direct-wired LEDs (or 28 RGB LEDs) or up to 2048 RGB LEDs in one or more serial strings.
The LED definitions include the following fields:
| Field | Type | Description |
|---|---|---|
| Name | string | For a single RBG LED driven by a PD-LED RGB output or an LED string segment consisting of a single RGB LED, this is the name software will use to drive the LED. or For an LED string segment consisting of more than one RGB LED, this is the baseName without the index suffix, the full name including the index suffix is what the software will use to drive each LED. |
| Polarity | string | "True" if the LED turns on by controlling the anode. "False" if the LED turns on by controlling the cathode. |
| Number | string | For a single RGB LED driven by a PD-LED RGB output: This is a formatted string "Ax-Rr-Gg-Bb", where x is the board address, r is the output connected to an RGB's red input, g for the green output, and b for the blue output. The software only provisions RGB LEDs, but the hardware supports individual LEDs. If your module contains individual LEDs, you can control them in software by accessing only that color of the RBG LED defined here. or For an LED string segment consisting of a single RGB LED: This is a formatted string "Ax:Sa", where x is the board address, and a is the LED string index. The name of the LED is taken as given without appending an index. or For an LED string segment consisting of more than one RGB LED: This is a formatted string "Ax:Sa-Sb", where x is the board address, a is the starting LED string index, and b is the ending LED string index. This LED definition will be replaced by a set of LED definitions, baseName0,...,baseName{b-a}, with one definition for each RGB LED that composes this LED string segment. The application will never see the LED definition with just the baseName. Note: if using an LED string, your Module Definition File must also include an LEDStrings section to describe how the strings themselves should be defined. |
| MaxBrightness | double | A value between 0 and 1. Limits the available power range for an LED. This value is multiplied against the desired LED color value before the resulting value is sent to hardware. |
| Label | string | User-friendly string for displaying the LED name on graphics. |
| Tags | string | Comma-separated list of tags the software can optionally use. |
| Location | float[] | Geographic coordinate of the LED, in inches: [x, y, z]. |
| MapIntoSpecialLEDFeatures | string | Used for individually controlled features mapped to a PD-LED output, such as a motor control line. When "True", this item won't appear in the P3's LED Diagnostics. |
| DependentSwitch | object | Ensures the switch is the desired state at startup. If not, this item will be ignored by the configuration logic. This a JSON object of the form: {"SwitchName": string, "SwitchActive": bool}. For example {"SwitchName": "servoWS", "SwitchActive": false} |
The LED definitions created from an LED string segment will all share the same location after reading the module definition file. The module driver must include code to assign the correct locations after the fact, otherwise the LED simulator will display these LEDs all on top of each other, and games will not be able to compute light show sweeps correctly.
Example:
This section describes WS2812-compatible strings of LEDs, each driven by a single string output from a Multimorphic PD-LED boards (available from Multimorphic). The StartingIndex and EndingIndex are RGB indices. The first LED element will be at 3*StartingIndex and the last LED element will be at 3*EndingIndex+2.
The LEDString definitions include the following fields:
| Field | Type | Description |
|---|---|---|
| Name | string | Name of the LEDString. Usually something generic like "Board 9 - String 0" |
| Number | string | This is a formatted string Ax-WS2812-a, where x is the board address and a is the string output (usually 0 to 2). |
| Polarity | string | "True" for LEDs that turn on with a high control signal. "False" for LEDs that turn on with a low control signal. |
| RGBOrder | string | Typically "GRB" for a WS2812 string |
| StartingIndex | int | The starting LED index for the first color of the first RGB LED in a string, as referenced in the PD-LED's LED indexing. |
| EndingIndex | int | The ending LED index for the last color of the last RGB LED in a string, as referenced in the PD-LED's LED indexing. |
| Label | string | User-friendly string for displaying the LEDString name on graphics. |
| Tags | string | Comma-separated list of tags the software can optionally use. |
Example:
This section describes each servo on the playfield module that is wired to a Multimorphic PD-LED board (available from Multimorphic). Each PD-LED board can control the operation of up to 12 servos.
The servo definitions include the following fields:
| Field | Type | Description |
|---|---|---|
| Name | string | Name of the servo motor. This is the name software will use to drive the motor. |
| Number | string | This is a formatted string Ax-y, where x is the address of the PD-LED board, and y is the index of the servo on the board (0-11, refer to the PD-LED board specifications). |
| Label | string | User-friendly string for displaying the motor name on graphics. |
| Tags | string | Comma-separated list of tags the software can optionally use. |
Example:
This section describes each stepper motor on the playfield module that is wired to a Multimorphic PD-LED board (available from Multimorphic). Each PD-LED board can control the operation of up to 2 stepper motors, connected through a separate stepper motor driver circuit.
The stepper motor definitions include the following fields:
| Field | Type | Description |
|---|---|---|
| Name | string | Name of the stepper motor. This is the name software will use to drive the motor. |
| Number | string | This is a formatted string Ax-y, where x is the address of the PD-LED board, and y is the index of the stepper motor on the board (0 or 1, refer to the PD-LED board specifications). |
| Label | string | User-friendly string for displaying the motor name on graphics. |
| Tags | string | Comma-separated list of tags the software can optionally use. |
Example:
This section describes definitions of BallPaths, which allow a game application to make use of playfield-specific shots and targets even if the application has no specific knowledge about which playfield is installed in the P3 at run-time. This section is therefore REQUIRED in all module drivers for all shots that aren't simply entrances into TroughLaunchers that aren't handled by a module driver. Said another way, if a shot does not go into a TroughLauncher or if a shot goes into a TroughLauncher and the module driver handles that entrance and posts other events, the shot needs to be defined here.
The events defined in BallPaths must be implemented in the associated module driver code. The module driver is what determines that a shot starts or completes, and then it posts the associated Started and Completed events defined in the BallPath definitions.
The BallPath definitions include the following fields:
| Field | Type | Description |
|---|---|---|
| Name | string | Name of the BallPath. This is the name software will use to reference the BallPath. |
| Tags | string[] | Array of tags the software can optionally use. |
| ExitType | string | String name of the associated Multimorphic.NetProcMachine.Config.BallPathExitType enum. See below for the available values. |
| EntranceName | string | String name of the entrance into the shot (can be anything) |
| ExitName | string | String name of the exit of the shot (can be anything) |
| StartedEvent | string | Event name that's posted when the shot is started (ie. a ball hits the first switch in a loop) |
| CompletedEvent | string | Event name that's posted when the shot is completed (ie. a ball completes a loop) |
| EntrancePosition | float[] | Geographic coordinate of the shot entrance, in inches: [x, y, z] |
| ExitPosition | float[] | Geographic coordinate of the shot exit, in inches: [x, y, z] |
| EntranceLEDs | string[][] | Array of arrays of LED segments. The first dimension is typically for parallel arrays, like the inside and outside strings of LEDs on a Cosmic Cart Racing ramp. The second dimension is the sequence of LEDs, starting closest to the shot entrance. An LED segment can either be an LED name denoting an individual LED, or a formatted string basenameX-Y denoting an LED string segment, where basename is the LED name without an index, X is the starting index and Y is the ending index, inclusive. The SDK will replace basenameX-Y by splicing in its place the sequence of LED names basenameX,...,basenameY. The application will never see the basenameX-Y notation. If no LEDs are associated with the shot, use [[""]]. |
| ExitLEDs | string[][] | Array of arrays of LED segments. The first dimension is typically for parallel arrays, like the inside and outside strings of LEDs on a Cosmic Cart Racing ramp. The second dimension is the sequence of LEDs, starting closest to the shot exit. An LED segment can either be an LED name denoting an individual LED, or a formatted string basenameX-Y denoting an LED string segment, where basename is the LED name without an index, X is the starting index and Y is the ending index, inclusive. The SDK will replace basenameX-Y by splicing in its place the sequence of LED names basenameX,...,basenameY. The application will never see the basenameX-Y notation. If no LEDs are associated with the shot, use [[""]]. |
Example:
In the example, the EntranceLEDs will be expanded into:
The ExitType describes what happens to the ball when the BallPath is completed. The options are:
| ExitType | Description |
|---|---|
| Undefined | Reserved for use by the module driver, typically for error handling. This is not a user-makeable shot. Module agnostic games should ignore this BallPath. |
| Other | Choose this when none of the other options apply |
| PlayfieldLocation | Ball remains in play somewhere on the playfield |
| Hole | Ball falls into the trough and is no longer in play |
| Lock | Ball enters a physical lock and is no longer in play |
| TemporaryLock | Ball may take a while to exit, but remains in play, for example a pop area. |
| Target | Ball activates a Switch and remains in play |
Suggested Tags to choose from:
| Tag | Description |
|---|---|
| Default | This dynamic BallPath is active by default when the application starts. |
| Hole | The ball enters a hole when completing this BallPath. |
| Inaccessible | This BallPath is used to reposition a mech so that the ball can no longer enter the entrance. The Started and Completed events will never be fired. |
| Lock | The ball enters a physical lock when completing this BallPath. |
| Loop | This BallPath is an orbit. |
| Passthrough | The ball remains in play and is free to move after completing the BallPath, without intervention from the application. |
| Ramp | This BallPath is a ramp. |
| Scoop | The ball enters a scoop when completing this BallPath. |
| Spinner | This BallPath may complete multiple times for a single shot. The application might choose to implement a cool down period to ignore the subsequent events if it wants to count the shot only once. |
| Static | This BallPath does not change and is always available (should be the only one with this entrance name). |
| Target | This BallPath is a Target. |
Some conventions to keep in mind when designing your BallPaths:
The development kit includes a number of existing module drivers so that developers can create new apps that work with those modules. Each has a module definition file that can serve as an example.
So that game apps can interact with the features on your module, you'll likely need to develop a module driver DLL. An example module driver DLL project is included in the development kit as a Visual Studio project called SampleModuleDriver. The code generally includes handling for custom launch destinations, ball paths, event-based control of specific playfield module features, etc.
A module Driver DLL must contain:
If a playfield module has any complex launching mechs, such as a multi-stage launcher or a launcher with a diverter, the playfield module definition file should include the "CustomCode" property on the associated TroughLauncher. Then, when a game app requests a launch out of that TroughLauncher, the platform launching code will post the ModeToMode event "Evt_CustomLaunchPrep" with a TroughLauncherDefinition param. The playfield module driver should subscribe to that event and use the TroughLauncherDefinition to see which TroughLauncher is being used for the launch. The actual launch is then paused (except for a timeout timer) until the module driver posts a response. See more details below:
ModeToMode events posted to module driver:
| Event Name | Parameter Type | Description |
|---|---|---|
| Evt_CustomLaunchPrep | TroughLauncherDefinition | Posted when beginning a custom launch, telling the module driver to do whatever it needs to do before the TroughLauncher should attempt to kick up a ball. The module driver should do what it needs to do and then post a response (see below responses) to signal it's ready for completion or to delay the launch logic from timing out. |
| Evt_CustomLaunchFollowUp | TroughLauncherDefinition | If the module driver requested a "LaunchBallAndPostCustomFollowUp" from the TroughLauncher in its response to the Evt_CustomLaunchPrep event, the TroughLauncher will post this event after it kicks the ball up, telling the module driver to handle the ball and do any cleanup it needs to do before verifying the launch. The module driver should do what it needs to do and then post a response (see below responses) to confirm a launch success or failure. |
Response ModeToMode events posted to module driver:
| Event Name | Parameter Type | Description |
|---|---|---|
| Evt_CustomLaunchPrepComplete | Multimorphic.P3.Mechs.CustomLaunchResponse enum | When responding to an Evt_CustomLaunchPrep event, the module driver should indicate when the TroughLauncher should either LaunchBall or LaunchBallAndPostCustomFollowup (in the case there's more work to do after the ball is launched but before the full launch should be confirmed. |
| Evt_CustomLaunchStageComplete | Multimorphic.P3.Mechs.CustomLaunchResponse enum | This is used after a followup stage is completed after a ball is launched to either confirm the launch was a success or failure. |
| Evt_CustomLaunchResetRetryTimer | double | How much time to delay before timing out (TroughLaunchers will default to timing out a custom launch request after 2.0s) |
To help you make your module driver's diagnostic prefab and ensure it shows up properly, the P3 SDK includes a Unity project called SampleModuleDriverDiagnostics. It is a subset of the P3's full Diagnostics just for simulating your Playfield Module's Diagnostics routines. It includes a very simple example module driver prefab called Assets/SampleModuleDriver/SampleModuleDriver_Diags.prefab. To change this for your Module Driver, drag it into the heirarchy, modify it as desired (including renaming it), and then drag it back into a Project folder. Then, to export your asset bundle file, select the prefab in the Project window (not in the Hierarchy), and at the bottom of the inspector window, select the AssetBundle dropdown, and add a new module driver asset bundle name. Most Multimorphic module drivers call it <module_identifier>-diags-assets. Then to build it, click Assets -> Build AssetBundles. It should then appear in Assets/AssetBundles, and you can now copy it into your module driver folder in ~/.multimorphic/P3/ModuleDrivers/<module_identifier>/<module_driver_version>/. The example is simply a counter. The text element is defined in the prefab, and the code that sends counter updates is in the module driver code.
Follow these steps to build an installable package of your module driver for your P3. In Unity, select from the top menu Multimorphic->"Package Module For Distribution". Fill in the fields in the dialog that appears and click "Continue". An internet connection is required.
When the process completes, you should have a new .p3p file within your project's Packages directory. The dialog also offers the option to write a copy of the .p3p file to a USB drive during the build.
The .p3p file can then be installed on your P3 via a USB drive.
These are the fields presented in the packager dialog:
| Field | Description |
|---|---|
| Module Id | The module identifier |
| Version | Module driver version (recommended format: a.b.c.d) |
| Files to Include | The path to a folder. All files within the folder will be included in the package. This folder should contain the module driver DLL, the module definition file, the diagnostics asset bundle and a document describing the module driver API to software developers. |