Skip to content

Commit

Permalink
Merge pull request #1714 from missionpinball/dev
Browse files Browse the repository at this point in the history
Merge current dev into 0.56.x to create 0.56.2
  • Loading branch information
toomanybrians authored Sep 16, 2023
2 parents 777af07 + f1fdc97 commit f3ce566
Show file tree
Hide file tree
Showing 40 changed files with 396 additions and 71 deletions.
3 changes: 2 additions & 1 deletion AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ their spare time, unpaid, for the love of pinball!
* James Cardona
* Dave Ensminger <dave@ensadi.com>
* Charles Duncan (nullbuilds)
* Eric Selk <ericselk2018@gmail.com>

MPF is inspired by pyprocgame and skeletongame which were written by:

Expand All @@ -39,4 +40,4 @@ MPF is inspired by pyprocgame and skeletongame which were written by:
* Michael Ocean
* Josh Kugler

Want to contribute to MPF? Get started here: http://docs.missionpinball.org/en/latest/about/contributing_to_mpf.html
Want to contribute to MPF? Get started here: http://docs.missionpinball.org/about/contributing_to_mpf.html
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
See: http://docs.missionpinball.org/en/dev/about/contributing_to_mpf.html
See: https://missionpinball.org/about/contributing_to_mpf/
38 changes: 16 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,13 @@ Mission Pinball Framework (MPF)
What is Mission Pinball Framework?
----------------------------------

Mission Pinball Framework (MPF) is an open source, cross-platform software for powering real pinball
machines in restaurants, bars, arcades, and elsewhere. MPF is a community-developed project released under the MIT license. It's supported by volunteers in their spare time. Individual pinball hardware makers are responsible for their own platform interface maintenance and contributions.
Mission Pinball Framework (MPF) is open source, cross-platform software for powering real pinball
machines. MPF is a community-developed project released under the MIT license. It's supported by volunteers in their spare time.

[![Coverage Status](https://coveralls.io/repos/missionpinball/mpf/badge.svg?branch=dev&service=github)](https://coveralls.io/github/missionpinball/mpf?branch=dev)
[![Test Status](https://github.com/missionpinball/mpf/actions/workflows/run_tests.yml/badge.svg)](https://github.com/missionpinball/mpf/actions/workflows/run_tests.yml)
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/1687/badge)](https://bestpractices.coreinfrastructure.org/projects/1687)

Technology and Compatibility
----------------------------

You can use MPF as the software to run a custom-built machine, or (with appropriate interface hardware) existing Williams, Bally, Stern, or Data East pinball machines. MPF interfaces with machines via modern pinball controller hardware, including:

* FAST Pinball controllers
* CobraPin
* Stern SPIKE / SPIKE 2
* Multimorphic P-ROC or P3-ROC
* Open Pinball Project (OPP) open source hardware
* LISY Platform
* Penny K Arcade PKONE
* Arduino Pinball Controller
* Plus many more systems & devices!

MPF is written in Python. It can be run on Windows, Mac, Linux, and Raspberry Pi host machines using the same code and configurations.

Visit the MPF project homepage at https://missionpinball.org. Additional related projects exist as part of the MPF ecosystem, including the "MPF Monitor" which is a graphical application that lets you simulate pinball hardware, and "MPF-MC" which is a media controller which provides graphics and sounds for pinball machines.

Documentation
Expand All @@ -43,13 +26,24 @@ Documentation
Support
-------

MPF is open source and has no official support. Some MPF users follow the MPF-users Google group: https://groups.google.com/forum/#!forum/mpf-users. Individual hardware providers may provide additional support for users of their hardware.
MPF is an open source community project which has no official support. Some MPF users participate in the MPF-Users Google group: https://groups.google.com/forum/#!forum/mpf-users.

Individual pinball hardware companies may provide additional support for users of their hardware, often via their own Slack, Discord, or other chat groups. If you get stuck, you can ask for help in the MPF-users group, or you reach out to your hardware provider.

Maintenance, Pull Requests, & Bug Fixes
---------------------------------------

As a community project, we welcome pull requests and bug fixes. However, we do not have the resources to provide support for MPF. If you are interested in becoming a maintainer, please contact us at brian@missionpinball.org.

Bugs or other issues related to MPF itself can be posted to the [MPF Discussions page on GitHub](https://github.com/orgs/missionpinball/discussions).

Contributing
------------

MPF is a passion project created and maintained by volunteers. If you're a Python coder, documentation writer, or pinball maker, feel free to make a change and submit a pull request. For more information about contributing see the [Contributing Code](http://docs.missionpinball.org/en/latest/about/contributing_to_mpf.html)
and [Contributing Documentation](http://docs.missionpinball.org/en/latest/about/contributing_to_mpf_docs.html) pages.
Individual pinball hardware makers are responsible for their own platform interface maintenance and contributions.

If you're a Python coder, documentation writer, or pinball maker, feel free to make a change and submit a pull request. For more information about contributing see the [Contributing Code](http://docs.missionpinball.org/about/contributing_to_mpf.html)
and [Contributing Documentation](http://docs.missionpinball.org/about/contributing_to_mpf_docs.html) pages.

License
-------
Expand Down
2 changes: 1 addition & 1 deletion RELEASE.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
See: http://docs.missionpinball.org/en/latest/versions/release_notes.html
See: http://docs.missionpinball.org/versions/release_notes.html
4 changes: 2 additions & 2 deletions docs/code/machine_code.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ match up to any of MPF's built in devices. The elevator and claw unloader
in *Demolition Man* is a good example, and what we'll use here.

(You can read about how to download and run *Demo Man* in the
`example games section <http://docs.missionpinball.org/en/latest/example_games>`_
`example games section <http://docs.missionpinball.org/example_games>`_
section of the MPF User Documentation.)

Here's how to create a custom code class:
Expand All @@ -35,7 +35,7 @@ In the *Demo Man* example, it looks like this:
.. image:: /images/scriptlet.png

Add an empty ``__init__.py`` file into your folder to make it a package.
It become the package ``code`` and all your classes will be referenced as
It become the package ``code`` and all your classes will be referenced as
``code.file_name.ClassName``.

2. Open and edit your custom code class file
Expand Down
2 changes: 1 addition & 1 deletion docs/dev/event_annotations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ document the event in code and in the docs, we use a custom docblock annotation:
reason: The reason for this awesomeness is stated here.
'''
The event will be automatically added to the `event reference <http://docs.missionpinball.org/en/latest/events/index.html>`_
The event will be automatically added to the `event reference <http://docs.missionpinball.org/events/index.html>`_
on the next update of the documentation.
24 changes: 12 additions & 12 deletions docs/dev/mc.widget_player.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ The widget player is available via: ``self.mc.widget_player``

Methods & Attributes
---------------------
``play(settings, context, calling_context)``
``play(settings, context, calling_context)``

``Add``, ``update`` or ``remove`` widget based on config

Expand Down Expand Up @@ -38,11 +38,11 @@ So here is our base ``widget`` from the config file that we will be using.
some_image_widget:
- type: image
image: this_image_is_wrong
y: 20
y: 20
x: 35
Refer to the widget section in the docs for more info on how to set it up:
http://docs.missionpinball.org/en/latest/displays/widgets/index.html
http://docs.missionpinball.org/displays/widgets/index.html

Writing the settings to show/play this widget in code
^^^^^^^^^^^^^^^
Expand All @@ -67,9 +67,9 @@ When it comes to the settings we start with the following:
}
}
You need to add ``action`` and ``key`` to make the ``widget`` work.
You need to add ``action`` and ``key`` to make the ``widget`` work.
Refer to the ``widget_player`` section for more info on these and what other functions can be added:
http://docs.missionpinball.org/en/latest/config/widget_player.html
http://docs.missionpinball.org/config/widget_player.html

Now you can show the pre-defined widget from the config file.

Expand All @@ -86,13 +86,13 @@ First we will define a ``variable`` which will hold our image name. (for example
character_name = some_function_for_retrieving_a_string()
image_name = “character_{}_profile_image”.format(character_name)
To keep things organized in the image folder we made a prefix for the image.
To keep things organized in the image folder we made a prefix for the image.
Make sure you add the images with the right syntax in the image folder.

The following code shows how to override an image and x-coordinate

.. code-block:: python
settings = {
"some_image_widget": {
"action": "add",
Expand All @@ -104,10 +104,10 @@ The following code shows how to override an image and x-coordinate
}
}
You can ``change``/``add`` everything this way from the related type of ``widget``, or the common settings for all widgets.
You can ``change``/``add`` everything this way from the related type of ``widget``, or the common settings for all widgets.
Refer to the common settings for a overview of all settings.

http://docs.missionpinball.org/en/latest/displays/widgets/common_settings.html
http://docs.missionpinball.org/displays/widgets/common_settings.html

Just make sure you format this way

Expand All @@ -127,7 +127,7 @@ Creating animation from predefined animations
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The easiest thing is to change/add pre-defined animations.
See capther 9 of widget animation for more info on this:
http://docs.missionpinball.org/en/latest/displays/widgets/animation.html
http://docs.missionpinball.org/displays/widgets/animation.html

.. code-block:: python
Expand All @@ -149,7 +149,7 @@ http://docs.missionpinball.org/en/latest/displays/widgets/animation.html
Make sure that after defining the event you put the animations in a list ``[]``. And put every animation between brackets ``{}``.
``“named_animation”`` is called like that, you don’t need to change it in something else.
Creating/overriding animation from within the widget
Creating/overriding animation from within the widget
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
When creating the animations within the widget, you want to make sure that you also want to create a list in here.
Expand Down
9 changes: 6 additions & 3 deletions mpf/commands/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,16 @@ def __init__(self, args, path):
def production_bundle(self):
"""Create a production bundle."""
config_loader = YamlMultifileConfigLoader(self.machine_path, self.args.configfile, False, False)
mpf_config = config_loader.load_mpf_config()
if self.args.mc:
mc_config = config_loader.load_mc_config()

mpf_config = config_loader.load_mpf_config()
if self.args.dest_path:
mpf_config.set_machine_path(self.args.dest_path)

if self.args.mc:
mc_config = config_loader.load_mc_config()
if self.args.dest_path:
mc_config.set_machine_path(self.args.dest_path)

pickle.dump(mpf_config, open(ProductionConfigLoader.get_mpf_bundle_path(self.machine_path), "wb"))
if self.args.mc:
pickle.dump(mc_config, open(ProductionConfigLoader.get_mpf_mc_bundle_path(self.machine_path), "wb"))
Expand Down
6 changes: 4 additions & 2 deletions mpf/config_players/show_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,10 @@ def _play(self, key, instance_dict, show, show_settings, queue, start_time, plac
start_step = show_settings['start_step'].evaluate(placeholder_args)
start_running = show_settings['start_running'].evaluate(placeholder_args)
show_tokens = {k: v.evaluate(placeholder_args) for k, v in show_settings['show_tokens'].items()}
speed = show_settings['speed'].evaluate(placeholder_args)

show_config = self.machine.show_controller.create_show_config(
show, show_settings['priority'], show_settings['speed'], show_settings['loops'], show_settings['sync_ms'],
show, show_settings['priority'], speed, show_settings['loops'], show_settings['sync_ms'],
show_settings['manual_advance'], show_tokens, show_settings['events_when_played'],
show_settings['events_when_stopped'], show_settings['events_when_looped'],
show_settings['events_when_paused'], show_settings['events_when_resumed'],
Expand All @@ -128,9 +129,10 @@ def _queue(self, key, instance_dict, show, show_settings, queue, start_time, pla

start_step = show_settings['start_step'].evaluate(placeholder_args)
show_tokens = {k: v.evaluate(placeholder_args) for k, v in show_settings['show_tokens'].items()}
speed = show_settings['speed'].evaluate(placeholder_args)

show_config = self.machine.show_controller.create_show_config(
show, show_settings['priority'], show_settings['speed'], show_settings['loops'], show_settings['sync_ms'],
show, show_settings['priority'], speed, show_settings['loops'], show_settings['sync_ms'],
show_settings['manual_advance'], show_tokens, show_settings['events_when_played'],
show_settings['events_when_stopped'], show_settings['events_when_looped'],
show_settings['events_when_paused'], show_settings['events_when_resumed'],
Expand Down
12 changes: 9 additions & 3 deletions mpf/config_spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,7 @@ high_score:
enter_initials_timeout: single|secs|20s
reverse_sort: list|str|None
reset_high_scores_events: list|event_handler|high_scores_reset,factory_reset
vars: dict|str:list|None
info_lights:
__valid_in__: machine # todo add to validator
__type__: config
Expand Down Expand Up @@ -1542,7 +1543,7 @@ show_player:
action: single|enum(play,stop,pause,resume,advance,step_back,update,queue)|play
show: single|str|None
priority: single|int_or_token|0
speed: single|float_or_token|1
speed: single|template_float_or_token|1
block_queue: single|bool|false
start_step: single|template_int|1
start_running: single|template_bool|True
Expand Down Expand Up @@ -1760,6 +1761,11 @@ sound_ducking:
sound_marker:
time: single|secs|
events: list|event_posted|
speedometers:
__valid_in__: machine, mode
__type__: device
start_switch: single|machine(switches)|None
stop_switch: single|machine(switches)|None
spi_bit_bang:
__valid_in__: machine
__type__: config
Expand Down Expand Up @@ -2191,8 +2197,8 @@ widgets:
rotation: single|int_or_token|0
scale: single|float_or_token|1.0
casing: single|str|None
# outline_color: single|kivycolor|ffffffff
# outline_width: single|int_or_token|0
outline_color: single|kivycolor|ffffffff
outline_width: single|int_or_token|0
# text_size: single|int_or_token|None # sets width of bounding box, not font
# shorten: single|bool_or_token|None
# mipmap: single|bool_or_token|None
Expand Down
4 changes: 4 additions & 0 deletions mpf/core/config_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ def get_machine_path(self):
"""Return machine path."""
return self._machine_path

def set_machine_path(self, value):
"""Set a new machine path."""
self._machine_path = value

def get_config_spec(self):
"""Return config spec."""
return self._config_spec
Expand Down
3 changes: 2 additions & 1 deletion mpf/core/config_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def __init__(self, machine, config_spec):
"lstr": self._validate_type_lstr,
"float": self._validate_type_float,
"float_or_token": self._validate_type_or_token(self._validate_type_float),
"template_float_or_token": self._validate_type_or_token(self._validate_type_template_float),
"int": self._validate_type_int,
"int_or_token": self._validate_type_or_token(self._validate_type_int),
"num": self._validate_type_num,
Expand Down Expand Up @@ -454,7 +455,7 @@ def _validate_type_template_str(self, item, validation_failure_info):

return self.machine.placeholder_manager.build_quoted_string_template(item)

def _validate_type_template_float(self, item, validation_failure_info):
def _validate_type_template_float(self, item, validation_failure_info, param=None):
if item is None:
return None
if not isinstance(item, (str, float, int)):
Expand Down
5 changes: 4 additions & 1 deletion mpf/core/device_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,11 +306,14 @@ def items_tagged(self, tag) -> List["Device"]:
Args:
----
tag: A string of the tag name which specifies what devices are
returned.
returned. A value of "*" returns all devices.
Returns a list of device objects. If no devices are found with that tag, it
will return an empty list.
"""
if tag == "*":
return self.values()

items_in_tag_cache = self._tag_cache.get(tag, None)
if items_in_tag_cache is not None:
return items_in_tag_cache
Expand Down
41 changes: 41 additions & 0 deletions mpf/core/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,47 @@ def add_handler(self, event: str, handler: Any, priority: int = 1, blocking_faci
Then later to remove all the handlers that a module added, you could:
for handler in handler_list:
``events.remove_handler(my_handler)``
A fully working example to get some initial working code might look like explained below. In your modes config file have the section
.. code::
mode:
start_events: ball_started
priority: 100
code: base.My_Base #base is the name of my code file (base.py), My_Base is the name of the class to be used from that source file
Here the mode being used is my base mode, of course it could be done for any mode. Some basic code to read and write some player variable might look like below.
.. code::
from mpf.core.mode import Mode
from mpf.core.events import event_handler
class My_Base(Mode): #base mode
def my_event_handler(self, *args, **kwargs):
print("My event handler is starting")
player = self.machine.game.player
if not player:
return # do something reasonable here but do not crash in the next line
# read player variable
print(player["status_target_light_red_0"]) #the variable status_target_light_red_0 is defined in the player_vars section of the config.yaml file
#with every fired event alternate variable value between 0 and 1
if(player["status_target_light_red_0"] == 0):
player["status_target_light_red_0"] = 1 #set the variable to a value
else:
player["status_target_light_red_0"] = 0
def mode_start(self, **kwargs):
print("My custom mode code is starting")
my_handler = self.machine.events.add_handler('toggle_light', self.my_event_handler)
"""
if event is None:
raise AssertionError("Cannot pass event None.")
Expand Down
7 changes: 4 additions & 3 deletions mpf/core/machine_vars.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ def load_machine_vars(self, machine_var_data_manager: DataManager, current_time)

continue

self.set_machine_var(name=name, value=settings['value'])
# Any value that was persisted before should be persisted again
self.set_machine_var(name=name, value=settings['value'], persist=True)

self._load_initial_machine_vars()

Expand Down Expand Up @@ -169,7 +170,7 @@ def configure_machine_var(self, name: str, persist: bool, expire_secs: int = Non
self.machine_vars[name]['expire_secs'] = expire_secs
self.machine_vars[name]['timeout'] = timeout

def set_machine_var(self, name: str, value: Any) -> None:
def set_machine_var(self, name: str, value: Any, persist=False) -> None:
"""Set the value of a machine variable.
Args:
Expand All @@ -178,7 +179,7 @@ def set_machine_var(self, name: str, value: Any) -> None:
value: The value you're setting. This can be any Type.
"""
if name not in self.machine_vars:
self.configure_machine_var(name=name, persist=False)
self.configure_machine_var(name=name, persist=persist)
prev_value = None
change = True
else:
Expand Down
Loading

0 comments on commit f3ce566

Please sign in to comment.