Source code for core.hacks

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""DFHack management."""

import collections
import filecmp
import os
import shutil
import sys

from . import log, paths
from .lnp import lnp


[docs]def open_dfhack_readme(): """Open the DFHack Readme in the default browser.""" from . import launcher index = paths.get('df', 'hack', 'docs', 'index.html') if os.path.isfile(index): launcher.open_file(index) else: launcher.open_url('https://dfhack.readthedocs.org')
[docs]def read_hacks(): """Reads which hacks are enabled.""" hacklines = [] for init_file in ('dfhack', 'onLoad', 'onMapLoad'): try: with open(paths.get('dfhack_config', init_file + '_PyLNP.init'), encoding='latin1') as f: hacklines.extend(line.strip() for line in f.readlines()) except IOError: log.debug(init_file + '_PyLNP.init not found.') return {name: hack for name, hack in get_hacks().items() if hack['command'] in hacklines}
[docs]def is_dfhack_enabled(): """Returns YES if DFHack should be used.""" if sys.platform == 'win32': if 'dfhack' not in lnp.df_info.variations: return False sdl = paths.get('df', 'SDL.dll') sdlreal = paths.get('df', 'SDLreal.dll') if not os.path.isfile(sdlreal): return False return not filecmp.cmp(sdl, sdlreal, 0) return lnp.userconfig.get_value('use_dfhack', True)
[docs]def toggle_dfhack(): """Toggles the use of DFHack.""" if sys.platform == 'win32': if 'dfhack' not in lnp.df_info.variations: return sdl = paths.get('df', 'SDL.dll') sdlhack = paths.get('df', 'SDLhack.dll') sdlreal = paths.get('df', 'SDLreal.dll') if is_dfhack_enabled(): shutil.copyfile(sdl, sdlhack) shutil.copyfile(sdlreal, sdl) else: shutil.copyfile(sdl, sdlreal) shutil.copyfile(sdlhack, sdl) else: lnp.userconfig['use_dfhack'] = not lnp.userconfig.get_value( 'use_dfhack', True) lnp.save_config()
[docs]def get_hacks(): """Returns dict of available hacks.""" return collections.OrderedDict(sorted( lnp.config.get_dict('dfhack').items(), key=lambda t: t[0]))
[docs]def get_hack(title): """ Returns the hack titled <title>, or None if this does not exist. Args: title: the title of the hack. """ try: return get_hacks()[title] except KeyError: log.d('No hack configured with name ' + title) return None
[docs]def toggle_hack(name): """ Toggles the hack <name>. Args: name: the name of the hack to toggle. Returns: True if the hack is now enabled, False if the hack is now disabled, None on error (no change in status) """ # Setup - get the hack, which file, and validate hack = get_hack(name) init_file = hack.get('file', 'dfhack') if init_file not in ('dfhack', 'onLoad', 'onMapLoad'): log.e('Illegal file configured for hack %s; must be one of ' '"dfhack", "onLoad", "onMapLoad"', name) return None # Get the enabled hacks for this file, and toggle our state hacks = {name: h for name, h in read_hacks().items() if h.get('file', 'dfhack') == init_file} is_enabled = False if not hacks.pop(name, False): is_enabled = True hacks[name] = hack # Write back to the file fname = paths.get('dfhack_config', init_file + '_PyLNP.init') log.i('Rebuilding {} with the enabled hacks'.format(fname)) lines = ['# {}\n# {}\n{}\n\n'.format( k, h['tooltip'].replace('\n', '\n#'), h['command']) for k, h in hacks.items()] if lines: with open(fname, 'w', encoding='latin1') as f: f.write('# Generated by PyLNP\n\n') f.writelines(lines) elif os.path.isfile(fname): os.remove(fname) return is_enabled