Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance DLL search on Windows #1649

Merged
merged 7 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 11 additions & 19 deletions openage/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,27 +31,15 @@ def print_version():
sys.exit(0)


def add_dll_search_paths(dll_paths):
def add_dll_search_paths(dll_paths: list[str]):
"""
This function adds DLL search paths.
This function does nothing if current OS is not Windows.
"""
from .util.dll import DllDirectoryManager

def close_windows_dll_path_handles(dll_path_handles):
"""
This function calls close() method on each of the handles.
"""
for handle in dll_path_handles:
handle.close()
manager = DllDirectoryManager(dll_paths)

if sys.platform != 'win32' or dll_paths is None:
return

import atexit
win_dll_path_handles = []
for addtional_path in dll_paths:
win_dll_path_handles.append(os.add_dll_directory(addtional_path))
atexit.register(close_windows_dll_path_handles, win_dll_path_handles)
return manager


def main(argv=None):
Expand All @@ -62,11 +50,11 @@ def main(argv=None):
)

if sys.platform == 'win32':
import inspect
from .util.dll import default_paths
cli.add_argument(
"--add-dll-search-path", action='append', dest='dll_paths',
# use path of current openage executable as default
default=[os.path.dirname(os.path.abspath(inspect.getsourcefile(lambda: 0)))],
default=default_paths(),
help="(Windows only) provide additional DLL search path")

cli.add_argument("--version", "-V", action='store_true', dest='print_version',
Expand Down Expand Up @@ -141,8 +129,10 @@ def main(argv=None):

args = cli.parse_args(argv)

dll_manager = None
if sys.platform == 'win32':
add_dll_search_paths(args.dll_paths)
dll_manager = add_dll_search_paths(args.dll_paths)
dll_manager.add_directories()

if args.print_version:
print_version()
Expand All @@ -151,6 +141,8 @@ def main(argv=None):
# the user didn't specify a subcommand. default to 'main'.
args = main_cli.parse_args(argv)

args.dll_manager = dll_manager

# process the shared args
set_loglevel(verbosity_to_level(args.verbose - args.quiet))

Expand Down
69 changes: 32 additions & 37 deletions openage/convert/processor/export/media_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import os
import multiprocessing
import queue
import sys

from openage.convert.entity_object.export.texture import Texture
from openage.convert.service import debug_info
Expand All @@ -27,6 +28,7 @@
from openage.convert.value_object.read.media.colortable import ColorTable
from openage.convert.value_object.init.game_version import GameVersion
from openage.util.fslike.path import Path
from openage.util.dll import DllDirectoryManager


class MediaExporter:
Expand Down Expand Up @@ -126,7 +128,8 @@ def export(
handle_outqueue_func,
itargs,
kwargs,
args.jobs
args.jobs,
args.dll_manager,
)

if args.debug_info > 5:
Expand Down Expand Up @@ -198,6 +201,7 @@ def _export_singlethreaded(
idx,
source_data,
single_queue,
None,
request.source_filename,
target_path,
*itargs,
Expand Down Expand Up @@ -225,7 +229,8 @@ def _export_multithreaded(
handle_outqueue_func: typing.Callable | None,
itargs: tuple,
kwargs: dict,
job_count: int = None
job_count: int = None,
dll_manager: DllDirectoryManager = None,
):
"""
Export media files in multiple threads.
Expand All @@ -241,15 +246,7 @@ def _export_multithreaded(
:param itargs: Arguments for the export function.
:param kwargs: Keyword arguments for the export function.
:param job_count: Number of worker processes to use.
:type requests: list[MediaExportRequest]
:type sourcedir: Path
:type exportdir: Path
:type read_data_func: typing.Callable
:type export_func: typing.Callable
:type handle_outqueue_func: typing.Callable
:type itargs: tuple
:type kwargs: dict
:type job_count: int
:param dll_manager: Adds DLL search paths for the subrocesses (Windows-only).
"""
worker_count = job_count
if worker_count is None:
Expand Down Expand Up @@ -297,6 +294,7 @@ def error_callback(exception: Exception):
idx,
source_data,
outqueue,
dll_manager,
request.source_filename,
target_path,
*itargs
Expand Down Expand Up @@ -625,6 +623,7 @@ def _export_blend(
request_id: int,
blendfile_data: bytes,
outqueue: multiprocessing.Queue,
dll_manager: DllDirectoryManager,
source_filename: str, # pylint: disable=unused-argument
targetdir: Path,
target_filename: str,
Expand All @@ -633,15 +632,16 @@ def _export_blend(
"""
Convert and export a blending mode.

:param request_id: ID of the export request.
:param blendfile_data: Raw file data of the blending mask.
:param outqueue: Queue for passing metadata to the main process.
:param dll_manager: Adds DLL search paths for the subrocesses (Windows-only).
:param target_path: Path to the resulting image file.
:param blend_mode_count: Number of blending modes extracted from the source file.
:type blendfile_data: bytes
:type outqueue: multiprocessing.Queue
:type target_path: openage.util.fslike.path.Path
:type blend_mode_count: int
"""
if sys.platform == "win32" and dll_manager is not None:
dll_manager.add_directories()

blend_data = Blendomatic(blendfile_data, blend_mode_count)

from .texture_merge import merge_frames
Expand All @@ -661,20 +661,23 @@ def _export_sound(
request_id: int,
sound_data: bytes,
outqueue: multiprocessing.Queue,
dll_manager: DllDirectoryManager,
source_filename: str, # pylint: disable=unused-argument
target_path: Path,
**kwargs # pylint: disable=unused-argument
) -> None:
"""
Convert and export a sound file.

:param request_id: ID of the export request.
:param sound_data: Raw file data of the sound file.
:param outqueue: Queue for passing metadata to the main process.
:param dll_manager: Adds DLL search paths for the subrocesses (Windows-only).
:param target_path: Path to the resulting sound file.
:type sound_data: bytes
:type outqueue: multiprocessing.Queue
:type target_path: openage.util.fslike.path.Path
"""
if sys.platform == "win32" and dll_manager is not None:
dll_manager.add_directories()

from ...service.export.opus.opusenc import encode
encoded = encode(sound_data)

Expand All @@ -691,6 +694,7 @@ def _export_terrain(
request_id: int,
graphics_data: bytes,
outqueue: multiprocessing.Queue,
dll_manager: DllDirectoryManager,
source_filename: str,
target_path: Path,
palettes: dict[int, ColorTable],
Expand All @@ -700,21 +704,19 @@ def _export_terrain(
"""
Convert and export a terrain graphics file.

:param request_id: ID of the export request.
:param graphics_data: Raw file data of the graphics file.
:param outqueue: Queue for passing the image metadata to the main process.
:param dll_manager: Adds DLL search paths for the subrocesses (Windows-only).
:param source_filename: Filename of the source file.
:param target_path: Path to the resulting image file.
:param palettes: Palettes used by the game.
:param compression_level: PNG compression level for the resulting image file.
:param game_version: Game edition and expansion info.
:type graphics_data: bytes
:type outqueue: multiprocessing.Queue
:type source_filename: str
:type target_path: openage.util.fslike.path.Path
:type palettes: dict
:type compression_level: int
:type game_version: GameVersion
"""
if sys.platform == "win32" and dll_manager is not None:
dll_manager.add_directories()

file_ext = source_filename.split('.')[-1].lower()
if file_ext == "slp":
from ...value_object.read.media.slp import SLP
Expand Down Expand Up @@ -758,6 +760,7 @@ def _export_texture(
request_id: int,
graphics_data: bytes,
outqueue: multiprocessing.Queue,
dll_manager: DllDirectoryManager,
source_filename: str,
target_path: Path,
palettes: dict[int, ColorTable],
Expand All @@ -770,20 +773,16 @@ def _export_texture(
:param request_id: ID of the export request.
:param graphics_data: Raw file data of the graphics file.
:param outqueue: Queue for passing the image metadata to the main process.
:param dll_manager: Adds DLL search paths for the subrocesses (Windows-only).
:param source_filename: Filename of the source file.
:param target_path: Path to the resulting image file.
:param palettes: Palettes used by the game.
:param compression_level: PNG compression level for the resulting image file.
:param cache_info: Media cache information with compression parameters from a previous run.
:type request_id: int
:type graphics_data: bytes
:type outqueue: multiprocessing.Queue
:type source_filename: str
:type target_path: openage.util.fslike.path.Path
:type palettes: dict
:type compression_level: int
:type cache_info: tuple
"""
if sys.platform == "win32" and dll_manager is not None:
dll_manager.add_directories()

file_ext = source_filename.split('.')[-1].lower()
if file_ext == "slp":
from ...value_object.read.media.slp import SLP
Expand Down Expand Up @@ -844,10 +843,6 @@ def _save_png(
:param target_path: Path to the resulting image file.
:param compression_level: PNG compression level used for the resulting image file.
:param dry_run: If True, create the PNG but don't save it as a file.
:type texture: Texture
:type target_path: openage.util.fslike.path.Path
:type compression_level: int
:type dry_run: bool
"""
from ...service.export.png import png_create

Expand Down
8 changes: 7 additions & 1 deletion openage/convert/tool/singlefile.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# Copyright 2015-2023 the openage authors. See copying.md for legal info.
# Copyright 2015-2024 the openage authors. See copying.md for legal info.

"""
Convert a single slp/wav file from some drs archive to a png/opus file.
"""
from __future__ import annotations

import sys

from pathlib import Path

Expand Down Expand Up @@ -59,6 +60,11 @@ def main(args, error):
file_path = Path(args.filename)
file_extension = file_path.suffix[1:].lower()

if sys.platform == "win32":
from openage.util.dll import DllDirectoryManager, default_paths
dll_manager = DllDirectoryManager(default_paths())
dll_manager.add_directories()

if not (args.mode in ("sld", "drs-wav", "wav") or file_extension in ("sld", "wav")):
if not args.palettes_path:
raise RuntimeError("palettes-path needs to be specified for "
Expand Down
1 change: 1 addition & 0 deletions openage/util/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ add_py_modules(
bytequeue.py
context.py
decorators.py
dll.py
files.py
fsprinting.py
hash.py
Expand Down
Loading
Loading