Move to VCPKG for mo2-cmake. (#151)

* Oblivion Remastered updates
- Handle invalid JSON
- Remove outdated pak sorting code
- Start from 8999 for pak directories
- Leaves space for early loaders
- Update MagicLoader handling for more dir names

---------

Co-authored-by: Jeremy Rimpo <jeremy.rimpo@servermonkey.com>
This commit is contained in:
Mikaël Capelle
2025-05-29 10:59:13 +02:00
committed by GitHub
co-authored by Jeremy Rimpo
parent 7ce47ddc83
commit f35a6b087a
11 changed files with 145 additions and 55 deletions
+44
View File
@@ -0,0 +1,44 @@
name: Build Basic Games Plugin
on:
push:
branches: [master]
pull_request:
types: [opened, synchronize, reopened]
jobs:
build:
runs-on: windows-2022
steps:
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Set environmental variables
shell: bash
run: |
echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV
- uses: actions/checkout@v4
with:
path: build
- name: Configure Basic Games Plugin build
working-directory: ${{ github.workspace }}/build
shell: pwsh
run: |
cmake --preset vs2022-windows "-DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/install" "-DVCPKG_MANIFEST_FEATURES=standalone"
- name: Build Basic Games Plugin
working-directory: ${{ github.workspace }}/build
run: cmake --build vsbuild --config RelWithDebInfo
- name: Install Basic Games Plugin
working-directory: ${{ github.workspace }}/build
run: cmake --install vsbuild --config RelWithDebInfo
- name: Upload Basic Games Plugin artifact
uses: actions/upload-artifact@master
with:
name: basic_games
path: ${{ github.workspace }}/install/bin/plugins
+4 -9
View File
@@ -1,13 +1,8 @@
cmake_minimum_required(VERSION 3.16)
if(DEFINED DEPENDENCIES_DIR)
include(${DEPENDENCIES_DIR}/modorganizer_super/cmake_common/mo2.cmake)
else()
include(${CMAKE_CURRENT_LIST_DIR}/../cmake_common/mo2.cmake)
endif()
project(basic_games LANGUAGES NONE)
find_package(mo2-cmake CONFIG REQUIRED)
add_custom_target(basic_games ALL)
mo2_configure_python(basic_games
MODULE
TRANSLATIONS OFF)
mo2_configure_python(basic_games MODULE TRANSLATIONS OFF)
+17
View File
@@ -0,0 +1,17 @@
{
"configurePresets": [
{
"binaryDir": "${sourceDir}/vsbuild",
"toolchainFile": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
"generator": "Visual Studio 17 2022",
"name": "vs2022-windows"
}
],
"buildPresets": [
{
"name": "vs2022-windows",
"configurePreset": "vs2022-windows"
}
],
"version": 4
}
+4 -6
View File
@@ -13,11 +13,9 @@ import mobase
from ..basic_features import BasicGameSaveGameInfo
from ..basic_game import BasicGame
from .oblivion_remaster.constants import PLUGIN_NAME
from .oblivion_remaster.constants import DEFAULT_UE4SS_MODS, PLUGIN_NAME, UE4SSModInfo
from .oblivion_remaster.paks.widget import PaksTabWidget
from .oblivion_remaster.ue4ss.widget import UE4SSModInfo, UE4SSTabWidget
DEFAULT_UE4SS_MODS = ["BPML_GenericFunctions", "BPModLoaderMod"]
from .oblivion_remaster.ue4ss.widget import UE4SSTabWidget
def getLootPath() -> Path | None:
@@ -286,11 +284,11 @@ class OblivionRemasteredGame(
if not ue4ss_mods_txt.exists():
with open(ue4ss_mods_txt.absoluteFilePath(), "w") as mods_txt:
for mod in DEFAULT_UE4SS_MODS:
mods_txt.write(f"{mod} : 1\n")
mods_txt.write(f"{mod['mod_name']} : 1\n")
if not ue4ss_mods_json.exists():
mods_data: list[UE4SSModInfo] = []
for mod in DEFAULT_UE4SS_MODS:
mods_data.append({"mod_name": mod, "mod_enabled": True})
mods_data.append({"mod_name": mod["mod_name"], "mod_enabled": True})
with open(ue4ss_mods_json.absoluteFilePath(), "w") as mods_json:
mods_json.write(json.dumps(mods_data, indent=4))
+13
View File
@@ -1 +1,14 @@
from typing import TypedDict
PLUGIN_NAME = "Oblivion Remastered Support Plugin"
class UE4SSModInfo(TypedDict):
mod_name: str
mod_enabled: bool
DEFAULT_UE4SS_MODS: list[UE4SSModInfo] = [
{"mod_name": "BPML_GenericFunctions", "mod_enabled": True},
{"mod_name": "BPModLoaderMod", "mod_enabled": True},
]
+8 -2
View File
@@ -82,8 +82,14 @@ class OblivionRemasteredDataContent(mobase.ModDataContent):
for paks_entry in entry:
if isinstance(paks_entry, mobase.IFileTree):
if paks_entry.name().casefold() == "~mods":
if paks_entry.find("MagicLoader"):
contents.add(Content.MAGIC_LOADER)
for mods_entry in paks_entry:
if isinstance(mods_entry, mobase.IFileTree):
if (
"magicloader"
in mods_entry.name().casefold()
):
contents.add(Content.MAGIC_LOADER)
break
if paks_entry.name().casefold() == "logicmods":
contents.add(Content.UE4SS)
case "movies":
+1 -1
View File
@@ -235,7 +235,7 @@ class PaksModel(QAbstractItemModel):
)
)
index = 9999
index = 8999
for row, pak in new_paks.items():
current_dir = QDir(pak[2])
parent_dir = QDir(pak[2])
+20 -28
View File
@@ -1,4 +1,3 @@
import re
from functools import cmp_to_key
from pathlib import Path
from typing import cast
@@ -69,7 +68,7 @@ class PaksTabWidget(QWidget):
def write_pak_files(self):
for index, pak in sorted(self._model.paks.items()):
name, _, current_path, target_path = pak
_, _, current_path, target_path = pak
if current_path and current_path != target_path:
path_dir = Path(current_path)
target_dir = Path(target_path)
@@ -77,30 +76,23 @@ class PaksTabWidget(QWidget):
target_dir.mkdir(parents=True, exist_ok=True)
if path_dir.exists():
for pak_file in path_dir.glob("*.pak"):
match = re.match(r"^(\d{4}_)?(.*)", pak_file.stem)
if not match:
continue
match_name = (
match.group(2) if match.group(2) else match.group(1)
ucas_file = pak_file.with_suffix(".ucas")
utoc_file = pak_file.with_suffix(".utoc")
for file in (pak_file, ucas_file, utoc_file):
if not file.exists():
continue
try:
file.rename(target_dir.joinpath(file.name))
except FileExistsError:
pass
data = self._model.paks[index]
self._model.paks[index] = (
data[0],
data[1],
data[3],
data[3],
)
if match_name == name:
ucas_file = pak_file.with_suffix(".ucas")
utoc_file = pak_file.with_suffix(".utoc")
for file in (pak_file, ucas_file, utoc_file):
if not file.exists():
continue
try:
file.rename(target_dir.joinpath(file.name))
except FileExistsError:
pass
data = self._model.paks[index]
self._model.paks[index] = (
data[0],
data[1],
data[3],
data[3],
)
break
break
if not list(path_dir.iterdir()):
path_dir.rmdir()
@@ -140,7 +132,7 @@ class PaksTabWidget(QWidget):
if isinstance(pak_mods, mobase.IFileTree):
for entry in pak_mods:
if is_directory(entry):
if entry.name().casefold() == "magicloader":
if "magicloader" in entry.name().casefold():
continue
for sub_entry in entry:
if (
@@ -179,7 +171,7 @@ class PaksTabWidget(QWidget):
QDir.Filter.Dirs | QDir.Filter.Files | QDir.Filter.NoDotAndDotDot
):
if entry.isDir():
if entry.completeBaseName().casefold() == "magicloader":
if "magicloader" in entry.completeBaseName().casefold():
continue
for sub_entry in QDir(entry.absoluteFilePath()).entryInfoList(
QDir.Filter.Files
@@ -207,7 +199,7 @@ class PaksTabWidget(QWidget):
sorted_paks = dict(sorted(paks.items(), key=cmp_to_key(pak_sort)))
shaken_paks: list[str] = self._shake_paks(sorted_paks)
final_paks: dict[str, tuple[str, str, str]] = {}
pak_index = 9999
pak_index = 8999
for pak in shaken_paks:
target_dir = pak_paths[pak][1] + "/" + str(pak_index).zfill(4)
final_paks[pak] = (pak_source[pak], pak_paths[pak][0], target_dir)
+11 -2
View File
@@ -1,4 +1,5 @@
import json
from json import JSONDecodeError
from typing import Any, Iterable
from PyQt6.QtCore import (
@@ -13,6 +14,8 @@ from PyQt6.QtWidgets import QWidget
import mobase
from ..constants import DEFAULT_UE4SS_MODS
class UE4SSListModel(QStringListModel):
def __init__(self, parent: QWidget | None, organizer: mobase.IOrganizer):
@@ -26,7 +29,10 @@ class UE4SSListModel(QStringListModel):
mods_json = QFileInfo(profile.absoluteFilePath("mods.json"))
if mods_json.exists():
with open(mods_json.absoluteFilePath(), "r") as json_file:
mod_data = json.load(json_file)
try:
mod_data = json.load(json_file)
except JSONDecodeError:
mod_data = DEFAULT_UE4SS_MODS
for mod in mod_data:
if mod["mod_enabled"]:
self._checked_items.add(mod["mod_name"])
@@ -37,7 +43,10 @@ class UE4SSListModel(QStringListModel):
mod_list: dict[str, bool] = {}
if mods_json.exists():
with open(mods_json.absoluteFilePath(), "r") as json_file:
mod_data = json.load(json_file)
try:
mod_data = json.load(json_file)
except JSONDecodeError:
mod_data = DEFAULT_UE4SS_MODS
for mod in mod_data:
mod_list[mod["mod_name"]] = mod["mod_enabled"]
for i in range(self.rowCount()):
+6 -7
View File
@@ -1,22 +1,18 @@
import json
from functools import cmp_to_key
from json import JSONDecodeError
from pathlib import Path
from typing import TypedDict
from PyQt6.QtCore import QDir, QFileInfo, Qt
from PyQt6.QtWidgets import QGridLayout, QWidget
import mobase
from ..constants import DEFAULT_UE4SS_MODS, UE4SSModInfo
from .model import UE4SSListModel
from .view import UE4SSView
class UE4SSModInfo(TypedDict):
mod_name: str
mod_enabled: bool
class UE4SSTabWidget(QWidget):
def __init__(self, parent: QWidget | None, organizer: mobase.IOrganizer):
super().__init__(parent)
@@ -155,7 +151,10 @@ class UE4SSTabWidget(QWidget):
mods_list: list[str] = []
if mods_json.exists() and mods_json.isFile():
with open(mods_json.absoluteFilePath(), "r") as json_file:
mods = json.load(json_file)
try:
mods = json.load(json_file)
except JSONDecodeError:
mods = DEFAULT_UE4SS_MODS
for mod in mods:
if mod["mod_enabled"]:
mods_list.append(mod["mod_name"])
+17
View File
@@ -0,0 +1,17 @@
{
"features": {
"standalone": {
"description": "Build Standalone.",
"dependencies": [
"mo2-cmake"
]
}
},
"vcpkg-configuration": {
"default-registry": {
"kind": "git",
"repository": "https://github.com/ModOrganizer2/vcpkg-registry",
"baseline": "69db61b22147b14ad66fd05cf798d855f6d68c12"
}
}
}