def __init__(self, machine): self.machine = machine self.registered_switches = CaseInsensitiveDict() # Dictionary of switches and states that have been registered for # callbacks. self.active_timed_switches = defaultdict(list) # Dictionary of switches that are currently in a state counting ms # waiting to notify their handlers. In other words, this is the dict that # tracks current switches for things like "do foo() if switch bar is # active for 100ms." self.switches = CaseInsensitiveDict() # Dictionary which holds the master list of switches as well as their # current states. State here does factor in whether a switch is NO or NC, # so 1 = active and 0 = inactive. # register for events self.machine.events.add_handler('timer_tick', self._tick, 1000) self.machine.events.add_handler('init_phase_2', self._initialize_switches, 1000) # priority 1000 so this fires first self.machine.events.add_handler('machine_reset_phase_3', self.log_active_switches)
def create_machine_var(self, name, value=0, persist=False, expire_secs=None, silent=False): """Creates a new machine variable: Args: name: String name of the variable. value: The value of the variable. This can be any Type. persist: Boolean as to whether this variable should be saved to disk so it's available the next time MPF boots. expire_secs: Optional number of seconds you'd like this variable to persist on disk for. When MPF boots, if the expiration time of the variable is in the past, it will be loaded with a value of 0. For example, this lets you write the number of credits on the machine to disk to persist even during power off, but you could set it so that those only stay persisted for an hour. """ var = CaseInsensitiveDict() var['value'] = value var['persist'] = persist var['expire_secs'] = expire_secs self.machine_vars[name] = var if not silent: self.set_machine_var(name, value, force_events=True)
def set_machine_var(self, name, value, force_events=False): """Sets the value of a machine variable. Args: name: String name of the variable you're setting the value for. value: The value you're setting. This can be any Type. force_events: Boolean which will force the event posting, the machine monitor callback, and writing the variable to disk (if it's set to persist). By default these things only happen if the new value is different from the old value. """ if name not in self.machine_vars: self.log.warning( "Received request to set machine_var '%s', but " "that is not a valid machine_var.", name) return prev_value = self.machine_vars[name]['value'] self.machine_vars[name]['value'] = value try: change = value - prev_value except TypeError: if prev_value != value: change = True else: change = False if change or force_events: if self.machine_vars[name]['persist']: disk_var = CaseInsensitiveDict() disk_var['value'] = value if self.machine_vars[name]['expire_secs']: disk_var['expire'] = ( time.time() + self.machine_vars[name]['expire_secs']) self.machine_var_data_manager.save_key(name, disk_var) self.log.debug( "Setting machine_var '%s' to: %s, (prior: %s, " "change: %s)", name, value, prev_value, change) self.events.post('machine_var_' + name, value=value, prev_value=prev_value, change=change) if self.machine_var_monitor: for callback in self.monitors['machine_vars']: callback(name=name, value=value, prev_value=prev_value, change=change)
def _get_merged_settings(self, section_name): # Returns a dict_merged dict of a config section from the machine-wide # config with the mode-specific config merged in. if section_name in self.machine.config: return_dict = copy.deepcopy(self.machine.config[section_name]) else: return_dict = CaseInsensitiveDict() if section_name in self.config: return_dict = Util.dict_merge(return_dict, self.config[section_name], combine_lists=False) return return_dict
def __init__(self, machine, config_section, path_string, asset_class, asset_attribute, file_extensions): self.log = logging.getLogger(config_section + ' Asset Manager') self.log.debug("Initializing...") self.machine = machine self.loader_thread.exception_queue = self.machine.crash_queue self.max_memory = None self.registered_assets = set() self.path_string = path_string self.config_section = config_section self.asset_class = asset_class self.file_extensions = file_extensions self.machine.asset_managers[config_section] = self if not hasattr(self.machine, asset_attribute): setattr(self.machine, asset_attribute, CaseInsensitiveDict()) self.asset_list = getattr(self.machine, asset_attribute) self.machine.mode_controller.register_load_method(self.load_assets, self.config_section, load_key='preload', priority=asset_class.load_priority) self.machine.mode_controller.register_start_method(self.load_assets, self.config_section, load_key='mode_start', priority=asset_class.load_priority) # register & load systemwide assets self.machine.events.add_handler('init_phase_4', self.register_and_load_machine_assets, priority=self.asset_class.load_priority) self.defaults = self.setup_defaults(self.machine.config)
def __init__(self, options): self.options = options self.log = logging.getLogger("Machine") self.log.info("Mission Pinball Framework v%s", version.__version__) self.log.debug("Command line arguments: {}".format(self.options)) self.verify_system_info() self.loop_start_time = 0 self.tick_num = 0 self.done = False self.machine_path = None # Path to this machine's folder root self.monitors = dict() self.plugins = list() self.scriptlets = list() self.modes = list() self.asset_managers = dict() self.game = None self.active_debugger = dict() self.machine_vars = CaseInsensitiveDict() self.machine_var_monitor = False self.machine_var_data_manager = None self.flag_bcp_reset_complete = False self.asset_loader_complete = False self.delay = DelayManager() self.crash_queue = Queue.Queue() Task.create(self._check_crash_queue) FileManager.init() self.config = dict() self._load_mpf_config() self._set_machine_path() self._load_machine_config() self.configure_debugger() self.hardware_platforms = dict() self.default_platform = None if not self.options['force_platform']: for section, platform in self.config['hardware'].iteritems(): if platform.lower() != 'default' and section != 'driverboards': self.add_platform(platform) self.set_default_platform(self.config['hardware']['platform']) else: self.add_platform(self.options['force_platform']) self.set_default_platform(self.options['force_platform']) # Do this here so there's a credit_string var even if they're not using # the credits mode try: credit_string = self.config['credits']['free_play_string'] except KeyError: credit_string = 'FREE PLAY' self.create_machine_var('credits_string', credit_string, silent=True) self._load_system_modules() # This is called so hw platforms have a change to register for events, # and/or anything else they need to do with system modules since # they're not set up yet when the hw platforms are constructed. for platform in self.hardware_platforms.values(): platform.initialize() self.validate_machine_config_section('machine') self.validate_machine_config_section('timing') self.validate_machine_config_section('hardware') self.validate_machine_config_section('game') self._register_system_events() self._load_machine_vars() self.events.post("init_phase_1") self.events._process_event_queue() self.events.post("init_phase_2") self.events._process_event_queue() self._load_plugins() self.events.post("init_phase_3") self.events._process_event_queue() self._load_scriptlets() self.events.post("init_phase_4") self.events._process_event_queue() self.events.post("init_phase_5") self.events._process_event_queue() self.reset()
def __init__(self, options): self.options = options self.log = logging.getLogger("MediaController") self.log.info("Media Controller Version %s", version.__version__) self.log.info("Backbox Control Protocol Version %s", version.__bcp_version__) self.log.info("Config File Version %s", version.__config_version__) python_version = sys.version_info self.log.info("Python version: %s.%s.%s", python_version[0], python_version[1], python_version[2]) self.log.info("Platform: %s", sys.platform) self.log.info("Python executable location: %s", sys.executable) self.log.info("32-bit Python? %s", sys.maxsize < 2**32) self.config = dict() self.done = False # todo self.machine_path = None self.asset_managers = dict() self.num_assets_to_load = 0 self.window = None self.window_manager = None self.pygame = False self.pygame_requested = False self.registered_pygame_handlers = dict() self.pygame_allowed_events = list() self.socket_thread = None self.receive_queue = Queue.Queue() self.sending_queue = Queue.Queue() self.crash_queue = Queue.Queue() self.game_modes = CaseInsensitiveDict() self.player_list = list() self.player = None self.HZ = 0 self.next_tick_time = 0 self.secs_per_tick = 0 Task.Create(self._check_crash_queue) self.bcp_commands = {'hello': self.bcp_hello, 'goodbye': self.bcp_goodbye, 'reset': self.reset, 'mode_start': self.bcp_mode_start, 'mode_stop': self.bcp_mode_stop, 'error': self.bcp_error, 'ball_start': self.bcp_ball_start, 'ball_end': self.bcp_ball_end, 'game_start': self.bcp_game_start, 'game_end': self.bcp_game_end, 'player_added': self.bcp_player_add, 'player_variable': self.bcp_player_variable, 'player_score': self.bcp_player_score, 'player_turn_start': self.bcp_player_turn_start, 'attract_start': self.bcp_attract_start, 'attract_stop': self.bcp_attract_stop, 'trigger': self.bcp_trigger, 'switch': self.bcp_switch, 'get': self.bcp_get, 'set': self.bcp_set, 'config': self.bcp_config, 'timer': self.bcp_timer } # load the MPF config & machine defaults self.config = ( Config.load_config_yaml(config=self.config, yaml_file=self.options['mcconfigfile'])) # Find the machine_files location. If it starts with a forward or # backward slash, then we assume it's from the mpf root. Otherwise we # assume it's from the subfolder location specified in the # mpfconfigfile location if (options['machinepath'].startswith('/') or options['machinepath'].startswith('\\')): machine_path = options['machinepath'] else: machine_path = os.path.join(self.config['mediacontroller']['paths'] ['machine_files'], options['machinepath']) self.machine_path = os.path.abspath(machine_path) # Add the machine folder to our path so we can import modules from it sys.path.append(self.machine_path) self.log.info("Machine folder: %s", machine_path) # Now find the config file location. Same as machine_file with the # slash uses to specify an absolute path if (options['configfile'].startswith('/') or options['configfile'].startswith('\\')): config_file = options['configfile'] else: if not options['configfile'].endswith('.yaml'): options['configfile'] += '.yaml' config_file = os.path.join(self.machine_path, self.config['mediacontroller']['paths'] ['config'], options['configfile']) self.log.info("Base machine config file: %s", config_file) # Load the machine-specific config self.config = Config.load_config_yaml(config=self.config, yaml_file=config_file) mediacontroller_config_spec = ''' exit_on_disconnect: boolean|True port: int|5050 ''' self.config['mediacontroller'] = ( Config.process_config(mediacontroller_config_spec, self.config['mediacontroller'])) self.events = EventManager(self) self.timing = Timing(self) # Load the media controller modules self.config['mediacontroller']['modules'] = ( self.config['mediacontroller']['modules'].split(' ')) for module in self.config['mediacontroller']['modules']: self.log.info("Loading module: %s", module) module_parts = module.split('.') exec('self.' + module_parts[0] + '=' + module + '(self)') # todo there's probably a more pythonic way to do this, and I know # exec() is supposedly unsafe, but meh, if you have access to put # malicious files in the system folder then you have access to this # code too. self.start_socket_thread() self.events.post("init_phase_1") self.events.post("init_phase_2") self.events.post("init_phase_3") self.events.post("init_phase_4") self.events.post("init_phase_5") self.reset()
def __init__(self, options): self.options = options self.log = logging.getLogger("MediaController") self.log.debug("Command line arguments: {}".format(self.options)) self.log.info("Media Controller Version %s", version.__version__) self.log.debug("Backbox Control Protocol Version %s", version.__bcp_version__) self.log.debug("Config File Version %s", version.__config_version__) python_version = sys.version_info if python_version[0] != 2 or python_version[1] != 7: self.log.error("Incorrect Python version. MPF requires Python 2.7." "x. You have Python %s.%s.%s.", python_version[0], python_version[1], python_version[2]) sys.exit() self.log.debug("Python version: %s.%s.%s", python_version[0], python_version[1], python_version[2]) self.log.debug("Platform: %s", sys.platform) self.log.debug("Python executable location: %s", sys.executable) self.log.debug("32-bit Python? %s", sys.maxsize < 2**32) self.active_debugger = dict() self.config = dict() self.done = False # todo self.machine_path = None self.asset_managers = dict() self.window = None self.window_manager = None self.pygame = False self.pygame_requested = False self.registered_pygame_handlers = dict() self.pygame_allowed_events = list() self.socket_thread = None self.receive_queue = Queue.Queue() self.sending_queue = Queue.Queue() self.crash_queue = Queue.Queue() self.modes = CaseInsensitiveDict() self.player_list = list() self.player = None self.HZ = 0 self.next_tick_time = 0 self.secs_per_tick = 0 self.machine_vars = CaseInsensitiveDict() self.machine_var_monitor = False self.tick_num = 0 self.delay = DelayManager() self._pc_assets_to_load = 0 self._pc_total_assets = 0 self.pc_connected = False Task.create(self._check_crash_queue) self.bcp_commands = {'ball_start': self.bcp_ball_start, 'ball_end': self.bcp_ball_end, 'config': self.bcp_config, 'error': self.bcp_error, 'get': self.bcp_get, 'goodbye': self.bcp_goodbye, 'hello': self.bcp_hello, 'machine_variable': self.bcp_machine_variable, 'mode_start': self.bcp_mode_start, 'mode_stop': self.bcp_mode_stop, 'player_added': self.bcp_player_add, 'player_score': self.bcp_player_score, 'player_turn_start': self.bcp_player_turn_start, 'player_variable': self.bcp_player_variable, 'reset': self.reset, 'set': self.bcp_set, 'shot': self.bcp_shot, 'switch': self.bcp_switch, 'timer': self.bcp_timer, 'trigger': self.bcp_trigger, } FileManager.init() self.config = dict() self._load_mc_config() self._set_machine_path() self._load_machine_config() # Find the machine_files location. If it starts with a forward or # backward slash, then we assume it's from the mpf root. Otherwise we # assume it's from the subfolder location specified in the # mpfconfig file location if (options['machine_path'].startswith('/') or options['machine_path'].startswith('\\')): machine_path = options['machine_path'] else: machine_path = os.path.join(self.config['media_controller']['paths'] ['machine_files'], options['machine_path']) self.machine_path = os.path.abspath(machine_path) # Add the machine folder to our path so we can import modules from it sys.path.append(self.machine_path) self.log.info("Machine folder: %s", machine_path) mediacontroller_config_spec = ''' exit_on_disconnect: boolean|True port: int|5050 ''' self.config['media_controller'] = ( Config.process_config(mediacontroller_config_spec, self.config['media_controller'])) self.events = EventManager(self, setup_event_player=False) self.timing = Timing(self) # Load the media controller modules self.config['media_controller']['modules'] = ( self.config['media_controller']['modules'].split(' ')) self.log.info("Loading Modules...") for module in self.config['media_controller']['modules']: self.log.debug("Loading module: %s", module) module_parts = module.split('.') exec('self.' + module_parts[0] + '=' + module + '(self)') # todo there's probably a more pythonic way to do this, and I know # exec() is supposedly unsafe, but meh, if you have access to put # malicious files in the system folder then you have access to this # code too. self.start_socket_thread() self.events.post("init_phase_1") self.events._process_event_queue() self.events.post("init_phase_2") self.events._process_event_queue() self.events.post("init_phase_3") self.events._process_event_queue() self.events.post("init_phase_4") self.events._process_event_queue() self.events.post("init_phase_5") self.events._process_event_queue() self.reset()