Merge branch 'rust-rewrite' into master

This commit is contained in:
Oliver Hamlet
2025-06-11 21:21:55 +01:00
251 changed files with 33700 additions and 16477 deletions
+6
View File
@@ -0,0 +1,6 @@
# Config for building the CXX wrapper against the debug MSVC runtime, so that it
# can be used from Debug builds of C++ code.
# From <https://github.com/dtolnay/cxx/issues/880#issuecomment-2521375384>
[env]
CFLAGS = "/MDd"
CXXFLAGS = "/MDd"
+15
View File
@@ -0,0 +1,15 @@
---
Language: Cpp
BasedOnStyle: Google
AccessModifierOffset: -2
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortIfStatementsOnASingleLine: false
BinPackArguments: false
BinPackParameters: false
BreakConstructorInitializers: AfterColon
ConstructorInitializerAllOnOneLineOrOnePerLine: true
FixNamespaceComments: false
SpaceAfterTemplateKeyword: false
Standard: Cpp11
...
+315
View File
@@ -0,0 +1,315 @@
cmake_minimum_required(VERSION 3.24)
if(POLICY CMP0135)
cmake_policy(SET CMP0135 NEW)
endif()
if(POLICY CMP0167)
cmake_policy(SET CMP0167 NEW)
endif()
project(libloot)
include(ExternalProject)
include(FetchContent)
include(CMakePackageConfigHelpers)
include(GNUInstallDirs)
option(BUILD_SHARED_LIBS "Build a shared library" ON)
option(RUN_CLANG_TIDY "Whether or not to run clang-tidy during build. Has no effect when using CMake's MSVC generator." OFF)
option(LIBLOOT_BUILD_TESTS "Whether or not to build libloot's tests." ON)
option(LIBLOOT_INSTALL_DOCS "Whether or not to install libloot's docs (which need to be built separately)." ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
##############################
# External Projects
##############################
if(MSVC)
set(LIBLOOT_CPP_FILENAME "libloot_cpp.lib")
else()
set(LIBLOOT_CPP_FILENAME "liblibloot_cpp.a")
endif()
if(DEFINED RUST_TARGET)
set(TARGET_PATH "${CMAKE_SOURCE_DIR}/../target/${RUST_TARGET}")
else()
set(TARGET_PATH "${CMAKE_SOURCE_DIR}/../target")
endif()
add_custom_target(libloot-cpp-build
COMMAND cargo build
$<$<NOT:$<CONFIG:Debug>>:--release>
$<$<AND:$<CONFIG:Debug>,$<PLATFORM_ID:Windows>>:--config>
$<$<AND:$<CONFIG:Debug>,$<PLATFORM_ID:Windows>>:${CMAKE_SOURCE_DIR}/.cargo/msvc-debug-config.toml>
$<$<BOOL:${RUST_TARGET}>:--target>
$<$<BOOL:${RUST_TARGET}>:${RUST_TARGET}>
BYPRODUCTS
"${TARGET_PATH}/$<IF:$<CONFIG:Debug>,debug,release>/${LIBLOOT_CPP_FILENAME}"
"${TARGET_PATH}/cxxbridge/libloot-cpp/src/lib.rs.cc"
"${TARGET_PATH}/cxxbridge/libloot-cpp/src/lib.rs.h"
"${TARGET_PATH}/cxxbridge/rust/cxx.h"
)
add_library(libloot-cpp INTERFACE)
add_dependencies(libloot-cpp libloot-cpp-build)
target_link_libraries(libloot-cpp INTERFACE
optimized "${TARGET_PATH}/release/${LIBLOOT_CPP_FILENAME}"
debug "${TARGET_PATH}/debug/${LIBLOOT_CPP_FILENAME}")
target_include_directories(libloot-cpp INTERFACE "${TARGET_PATH}/cxxbridge")
##############################
# General Settings
##############################
set(LIBLOOT_SRC_API_CPP_FILES
"${CMAKE_SOURCE_DIR}/src/api/api.cpp"
"${CMAKE_SOURCE_DIR}/src/api/convert.cpp"
"${CMAKE_SOURCE_DIR}/src/api/database.cpp"
"${CMAKE_SOURCE_DIR}/src/api/exception/cyclic_interaction_error.cpp"
"${CMAKE_SOURCE_DIR}/src/api/exception/exception.cpp"
"${CMAKE_SOURCE_DIR}/src/api/exception/undefined_group_error.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/file.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/filename.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/group.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/location.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/message.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/message_content.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/plugin_cleaning_data.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/plugin_metadata.cpp"
"${CMAKE_SOURCE_DIR}/src/api/metadata/tag.cpp"
"${CMAKE_SOURCE_DIR}/src/api/game.cpp"
"${CMAKE_SOURCE_DIR}/src/api/plugin.cpp"
"${CMAKE_SOURCE_DIR}/src/api/vertex.cpp")
set(LIBLOOT_INCLUDE_H_FILES
"${CMAKE_SOURCE_DIR}/include/loot/api.h"
"${CMAKE_SOURCE_DIR}/include/loot/api_decorator.h"
"${CMAKE_SOURCE_DIR}/include/loot/database_interface.h"
"${CMAKE_SOURCE_DIR}/include/loot/exception/cyclic_interaction_error.h"
"${CMAKE_SOURCE_DIR}/include/loot/exception/plugin_not_loaded_error.h"
"${CMAKE_SOURCE_DIR}/include/loot/exception/undefined_group_error.h"
"${CMAKE_SOURCE_DIR}/include/loot/enum/edge_type.h"
"${CMAKE_SOURCE_DIR}/include/loot/enum/game_type.h"
"${CMAKE_SOURCE_DIR}/include/loot/enum/log_level.h"
"${CMAKE_SOURCE_DIR}/include/loot/enum/message_type.h"
"${CMAKE_SOURCE_DIR}/include/loot/game_interface.h"
"${CMAKE_SOURCE_DIR}/include/loot/loot_version.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/file.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/filename.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/group.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/location.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/message.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/message_content.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/plugin_cleaning_data.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/plugin_metadata.h"
"${CMAKE_SOURCE_DIR}/include/loot/metadata/tag.h"
"${CMAKE_SOURCE_DIR}/include/loot/plugin_interface.h"
"${CMAKE_SOURCE_DIR}/include/loot/vertex.h")
set(LIBLOOT_SRC_API_H_FILES
"${CMAKE_SOURCE_DIR}/src/api/convert.h"
"${CMAKE_SOURCE_DIR}/src/api/database.h"
"${CMAKE_SOURCE_DIR}/src/api/exception/exception.h"
"${CMAKE_SOURCE_DIR}/src/api/game.h"
"${CMAKE_SOURCE_DIR}/src/api/plugin.h")
source_group(TREE "${CMAKE_SOURCE_DIR}/src/api"
PREFIX "Source Files"
FILES ${LIBLOOT_SRC_API_CPP_FILES})
source_group(TREE "${CMAKE_SOURCE_DIR}/include"
PREFIX "Header Files"
FILES ${LIBLOOT_INCLUDE_H_FILES})
source_group(TREE "${CMAKE_SOURCE_DIR}/src/api"
PREFIX "Header Files"
FILES ${LIBLOOT_SRC_API_H_FILES})
set(LIBLOOT_ALL_SOURCES
${LIBLOOT_SRC_API_CPP_FILES}
${LIBLOOT_INCLUDE_H_FILES}
${LIBLOOT_SRC_API_H_FILES}
"${CMAKE_SOURCE_DIR}/src/api/resource.rc")
##############################
# Define Targets
##############################
# Build API.
add_library(loot ${LIBLOOT_ALL_SOURCES})
target_link_libraries(loot PRIVATE libloot-cpp)
##############################
# Set Target-Specific Flags
##############################
set(LIBLOOT_INCLUDE_DIRS
"${CMAKE_SOURCE_DIR}/src"
"${CMAKE_SOURCE_DIR}/include")
set(LIBLOOT_COMMON_SYSTEM_INCLUDE_DIRS
${LIBLOADORDER_INCLUDE_DIRS}
${ESPLUGIN_INCLUDE_DIRS}
${LCI_INCLUDE_DIRS})
target_include_directories(loot PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
target_include_directories(loot PRIVATE ${LIBLOOT_INCLUDE_DIRS})
target_include_directories(loot SYSTEM PRIVATE
${LIBLOOT_COMMON_SYSTEM_INCLUDE_DIRS})
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
target_compile_definitions(loot PRIVATE UNICODE _UNICODE LOOT_EXPORT)
set(LOOT_LIBS ntdll ws2_32 bcrypt)
target_link_libraries(loot PRIVATE ${LOOT_LIBS})
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
target_compile_options(loot PRIVATE "-Wall" "-Wextra")
endif()
if(MSVC)
# Turn off permissive mode to be more standards-compliant and avoid compiler errors.
target_compile_options(loot PRIVATE "/permissive-" "/W4" "/Zc:__cplusplus" "/GL")
target_link_options(loot PRIVATE "/LTCG")
endif()
##############################
# Configure clang-tidy
##############################
if(RUN_CLANG_TIDY)
set(CLANG_TIDY_COMMON_CHECKS
"cppcoreguidelines-avoid-c-arrays"
"cppcoreguidelines-c-copy-assignment-signature"
"cppcoreguidelines-explicit-virtual-functions"
"cppcoreguidelines-init-variables"
"cppcoreguidelines-interfaces-global-init"
"cppcoreguidelines-macro-usage"
"cppcoreguidelines-narrowing-conventions"
"cppcoreguidelines-no-malloc"
"cppcoreguidelines-pro-bounds-array-to-pointer-decay"
"cppcoreguidelines-pro-bounds-constant-array-index"
"cppcoreguidelines-pro-bounds-pointer-arithmetic"
"cppcoreguidelines-pro-type-const-cast"
"cppcoreguidelines-pro-type-cstyle-cast"
"cppcoreguidelines-pro-type-member-init"
"cppcoreguidelines-pro-type-reinterpret-cast"
"cppcoreguidelines-pro-type-static-cast-downcast"
"cppcoreguidelines-pro-type-union-access"
"cppcoreguidelines-pro-type-vararg"
"cppcoreguidelines-pro-type-slicing")
set(CLANG_TIDY_LIB_CHECKS
${CLANG_TIDY_COMMON_CHECKS}
"cppcoreguidelines-avoid-goto"
"cppcoreguidelines-avoid-magic-numbers"
"cppcoreguidelines-non-private-member-variables-in-classes"
"cppcoreguidelines-special-member-functions")
list(JOIN CLANG_TIDY_LIB_CHECKS "," CLANG_TIDY_LIB_CHECKS_JOINED)
set(CLANG_TIDY_LIB
clang-tidy "-header-filter=.*" "-checks=${CLANG_TIDY_LIB_CHECKS_JOINED}")
set_target_properties(loot
PROPERTIES
CXX_CLANG_TIDY "${CLANG_TIDY_LIB}")
endif()
##############################
# Tests
##############################
if(LIBLOOT_BUILD_TESTS)
include("cmake/tests.cmake")
endif()
########################################
# Install
########################################
set(LIBLOOT_VERSION "0.27.0")
set_property(TARGET loot PROPERTY VERSION ${LIBLOOT_VERSION})
set_property(TARGET loot PROPERTY SOVERSION 0)
set_property(TARGET loot PROPERTY INTERFACE_libloot_MAJOR_VERSION 0)
set_property(TARGET loot APPEND PROPERTY COMPATIBLE_INTERFACE_STRING libloot_MAJOR_VERSION)
configure_package_config_file(
${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/liblootConfig.cmake"
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libloot
)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/liblootConfigVersion.cmake"
VERSION "${LIBLOOT_VERSION}"
COMPATIBILITY AnyNewerVersion
)
install(TARGETS loot
EXPORT liblootTargets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
if(MSVC)
install(FILES $<TARGET_PDB_FILE:loot>
DESTINATION ${CMAKE_INSTALL_LIBDIR}
OPTIONAL
CONFIGURATIONS RelWithDebInfo)
endif()
install(DIRECTORY "${CMAKE_SOURCE_DIR}/include/"
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
if(LIBLOOT_INSTALL_DOCS)
install(DIRECTORY "${CMAKE_SOURCE_DIR}/../docs/build/html/"
DESTINATION ${CMAKE_INSTALL_DOCDIR})
endif()
install(EXPORT liblootTargets
FILE liblootTargets.cmake
NAMESPACE libloot::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libloot)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/liblootConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/liblootConfigVersion.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libloot)
########################################
# CPack
########################################
if(NOT DEFINED CPACK_PACKAGE_VERSION)
find_package(Git)
if(GIT_FOUND)
execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --long --always --abbrev=7
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_DESCRIBE_STRING
OUTPUT_STRIP_TRAILING_WHITESPACE)
else()
set(GIT_DESCRIBE_STRING "unknown-version")
endif()
set(CPACK_PACKAGE_VERSION ${GIT_DESCRIBE_STRING})
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(CPACK_GENERATOR "7Z")
else()
set(CPACK_GENERATOR "TXZ")
endif()
set(CPACK_PACKAGE_DIRECTORY "${CMAKE_BINARY_DIR}/package")
include(CPack)
+17
View File
@@ -0,0 +1,17 @@
[package]
name = "libloot-cpp"
version = "0.27.0"
edition = "2024"
license = "GPL-3.0-or-later"
[dependencies]
cxx = { version = "1.0", features = ["c++17"] }
delegate = "0.13.2"
libloot = { path = ".." }
libloot-ffi-errors = { path = "../ffi-errors" }
[build-dependencies]
cxx-build = "1.0"
[lib]
crate-type = ["staticlib"]
+2480
View File
File diff suppressed because it is too large Load Diff
+79
View File
@@ -0,0 +1,79 @@
# libloot-rs C++ wrapper
This is a wrapper around libloot that provides a C++ interface that's ABI-compatible with libloot v0.27.0.
The wrapper has two layers:
- a static library built using Cargo, which provides a C++ interface
- a shared library built using CMake, which wraps that C++ interface to provide another that is ABI-compatible with C++ libloot.
## Building
libloot uses the following CMake variables to set build parameters:
Parameter | Values | Default |Description
----------|--------|---------|-----------
`BUILD_SHARED_LIBS` | `ON`, `OFF` | `ON` | Whether or not to build a shared libloot binary.
`LIBLOOT_BUILD_TESTS` | `ON`, `OFF` | `ON` | Whether or not to build libloot's tests.
`LIBLOOT_INSTALL_DOCS` | `ON`, `OFF` | `ON` | Whether or not to install libloot's docs (which need to be built separately).
`RUN_CLANG_TIDY` | `ON`, `OFF` | `OFF` | Whether or not to run clang-tidy during build. Has no effect when using CMake's MSVC generator.
### Windows
To build a release build with debug info:
```
cmake -B build .
cmake --build build --parallel --config RelWithDebInfo
```
To build a debug build:
```
cmake -B build .
cmake --build build --parallel --config Debug
```
### Linux
To build a release build with debug info:
```
cmake -B build . -DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake --build build --parallel
```
to build a debug build:
```
cargo build
cmake -B build . -DCMAKE_BUILD_TYPE=Debug
cmake --build build --parallel
```
### Tests
The build process also builds the test suite by default. To skip building the tests, pass `-DLIBLOOT_BUILD_TESTS=OFF` when first running CMake.
If built, the tests can be run using:
```
ctest --test-dir build --output-on-failure --parallel -V
```
### Documentation
Install [Doxygen](https://www.doxygen.nl/), Python and [uv](https://docs.astral.sh/uv/getting-started/installation/) and make sure they're accessible from your `PATH`, then run:
```
cd ../docs
uv run -- sphinx-build -b html . build/html
```
### Packaging
To package the build:
```
cpack --config build/CPackConfig.cmake -C RelWithDebInfo
```
+20
View File
@@ -0,0 +1,20 @@
fn main() {
cxx_build::bridge("src/lib.rs")
.std("c++17")
.flag_if_supported("/Zc:__cplusplus")
.flag_if_supported("/permissive-")
.compile("libloot-cpp");
// From <https://github.com/dtolnay/cxx/issues/880#issuecomment-2521375384>
if std::env::var("TARGET").is_ok_and(|s| s.contains("windows-msvc")) {
// MSVC compiler suite
if std::env::var("CFLAGS").is_ok_and(|s| s.contains("/MDd")) {
// debug runtime flag is set
// Don't link the default CRT
println!("cargo::rustc-link-arg=/nodefaultlib:msvcrt");
// Link the debug CRT instead
println!("cargo::rustc-link-arg=/defaultlib:msvcrtd");
}
}
}
+5
View File
@@ -0,0 +1,5 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/liblootTargets.cmake")
check_required_components(libloot)
+210
View File
@@ -0,0 +1,210 @@
##############################
# Dependencies
##############################
include(FetchContent)
include(GoogleTest)
set(BUILD_GMOCK OFF)
set(gtest_force_shared_crt ON)
set(INSTALL_GTEST OFF)
# Google Test doesn't have a scoped equivalent to BUILD_SHARED_LIBS, so set the
# global value and then set it back to the original value once Google Test has
# been configured.
set(BUILD_SHARED_LIBS_INITIAL ${BUILD_SHARED_LIBS})
set(BUILD_SHARED_LIBS OFF)
FetchContent_Declare(
GTest
URL "https://github.com/google/googletest/archive/refs/tags/v1.16.0.tar.gz"
URL_HASH "SHA256=78c676fc63881529bf97bf9d45948d905a66833fbfa5318ea2cd7478cb98f399"
FIND_PACKAGE_ARGS)
FetchContent_Declare(
testing-plugins
URL "https://github.com/Ortham/testing-plugins/archive/1.6.2.tar.gz"
URL_HASH "SHA256=f6e5b55e2669993ab650ba470424b725d1fab71ace979134a77de3373bd55620")
FetchContent_MakeAvailable(GTest testing-plugins)
set(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS_INITIAL})
##############################
# General Settings
##############################
set(LIBLOOT_SRC_TESTS_INTERNALS_CPP_FILES
"${CMAKE_SOURCE_DIR}/src/tests/api/internals/main.cpp")
# set(LIBLOOT_SRC_TESTS_INTERNALS_H_FILES)
set(LIBLOOT_SRC_TESTS_INTERFACE_CPP_FILES
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/main.cpp")
set(LIBLOOT_SRC_TESTS_INTERFACE_H_FILES
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/api_game_operations_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/create_game_handle_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/database_interface_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/game_interface_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/is_compatible_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/metadata/file_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/metadata/group_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/metadata/location_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/metadata/message_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/metadata/message_content_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/metadata/plugin_cleaning_data_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/metadata/plugin_metadata_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/api/interface/metadata/tag_test.h")
source_group(TREE "${CMAKE_SOURCE_DIR}/src/tests/api/internals"
PREFIX "Source Files"
FILES ${LIBLOOT_SRC_TESTS_INTERNALS_CPP_FILES})
# source_group(TREE "${CMAKE_SOURCE_DIR}/src/tests/api/internals"
# PREFIX "Header Files"
# FILES ${LIBLOOT_SRC_TESTS_INTERNALS_H_FILES})
source_group(TREE "${CMAKE_SOURCE_DIR}/src/tests/api/interface"
PREFIX "Source Files"
FILES ${LIBLOOT_SRC_TESTS_INTERFACE_CPP_FILES})
source_group(TREE "${CMAKE_SOURCE_DIR}/src/tests/api/interface"
PREFIX "Header Files"
FILES ${LIBLOOT_SRC_TESTS_INTERFACE_H_FILES})
set(LIBLOOT_INTERNALS_TESTS_ALL_SOURCES
${LIBLOOT_ALL_SOURCES}
${LIBLOOT_SRC_TESTS_INTERNALS_CPP_FILES}
# ${LIBLOOT_SRC_TESTS_INTERNALS_H_FILES}
"${CMAKE_SOURCE_DIR}/src/tests/common_game_test_fixture.h"
"${CMAKE_SOURCE_DIR}/src/tests/test_helpers.h"
"${CMAKE_SOURCE_DIR}/src/tests/printers.h")
set(LIBLOOT_INTERFACE_TESTS_ALL_SOURCES
${LIBLOOT_SRC_TESTS_INTERFACE_CPP_FILES}
${LIBLOOT_SRC_TESTS_INTERFACE_H_FILES}
"${CMAKE_SOURCE_DIR}/src/tests/common_game_test_fixture.h"
"${CMAKE_SOURCE_DIR}/src/tests/test_helpers.h"
"${CMAKE_SOURCE_DIR}/src/tests/printers.h")
##############################
# Define Targets
##############################
# Build tests.
add_executable(libloot_internals_tests ${LIBLOOT_INTERNALS_TESTS_ALL_SOURCES})
target_link_libraries(libloot_internals_tests PRIVATE
libloot-cpp
GTest::gtest_main)
# Build API tests.
add_executable(libloot_tests ${LIBLOOT_INTERFACE_TESTS_ALL_SOURCES})
add_dependencies(libloot_tests loot)
target_link_libraries(libloot_tests PRIVATE loot GTest::gtest_main)
enable_testing()
gtest_discover_tests(libloot_internals_tests DISCOVERY_TIMEOUT 10)
gtest_discover_tests(libloot_tests DISCOVERY_TIMEOUT 10)
##############################
# Set Target-Specific Flags
##############################
target_include_directories(libloot_internals_tests PRIVATE
${LIBLOOT_INCLUDE_DIRS})
target_include_directories(libloot_internals_tests SYSTEM PRIVATE
${LIBLOOT_COMMON_SYSTEM_INCLUDE_DIRS})
target_include_directories(libloot_tests PRIVATE ${LIBLOOT_INCLUDE_DIRS})
target_include_directories(libloot_tests SYSTEM PRIVATE
${LIBLOOT_COMMON_SYSTEM_INCLUDE_DIRS})
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
target_compile_definitions(libloot_internals_tests PRIVATE
UNICODE _UNICODE LOOT_STATIC)
target_compile_definitions(libloot_tests PRIVATE UNICODE _UNICODE)
if(NOT CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
target_compile_definitions(libloot_tests PRIVATE LOOT_STATIC)
endif()
target_link_libraries(libloot_internals_tests PRIVATE ${LOOT_LIBS})
target_link_libraries(libloot_tests PRIVATE ${LOOT_LIBS})
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
target_compile_options(libloot_internals_tests PRIVATE "-Wall" "-Wextra")
target_compile_options(libloot_tests PRIVATE "-Wall" "-Wextra")
endif()
if(MSVC)
# Turn off permissive mode to be more standards-compliant and avoid compiler errors.
target_compile_options(libloot_tests PRIVATE "/Zc:__cplusplus" "/permissive-" "/W4")
# Set /bigobj to allow building Debug and RelWithDebInfo tests
target_compile_options(libloot_internals_tests PRIVATE
"/Zc:__cplusplus"
"/permissive-"
"/W4"
"$<$<OR:$<CONFIG:DEBUG>,$<CONFIG:RelWithDebInfo>>:/bigobj>")
endif()
##############################
# Configure clang-tidy
##############################
if(RUN_CLANG_TIDY)
set(CLANG_TIDY_COMMON_CHECKS
"cppcoreguidelines-avoid-c-arrays"
"cppcoreguidelines-c-copy-assignment-signature"
"cppcoreguidelines-explicit-virtual-functions"
"cppcoreguidelines-init-variables"
"cppcoreguidelines-interfaces-global-init"
"cppcoreguidelines-macro-usage"
"cppcoreguidelines-narrowing-conventions"
"cppcoreguidelines-no-malloc"
"cppcoreguidelines-pro-bounds-array-to-pointer-decay"
"cppcoreguidelines-pro-bounds-constant-array-index"
"cppcoreguidelines-pro-bounds-pointer-arithmetic"
"cppcoreguidelines-pro-type-const-cast"
"cppcoreguidelines-pro-type-cstyle-cast"
"cppcoreguidelines-pro-type-member-init"
"cppcoreguidelines-pro-type-reinterpret-cast"
"cppcoreguidelines-pro-type-static-cast-downcast"
"cppcoreguidelines-pro-type-union-access"
"cppcoreguidelines-pro-type-vararg"
"cppcoreguidelines-pro-type-slicing")
# Skip some checks for tests because they're not worth the noise (e.g. GTest
# happens to use goto).
set(CLANG_TIDY_TEST_CHECKS ${CLANG_TIDY_COMMON_CHECKS})
list(JOIN CLANG_TIDY_TEST_CHECKS "," CLANG_TIDY_TEST_CHECKS_JOINED)
set(CLANG_TIDY_TEST
clang-tidy "-header-filter=.*" "-checks=${CLANG_TIDY_TEST_CHECKS_JOINED}")
set_target_properties(libloot_internals_tests libloot_tests
PROPERTIES
CXX_CLANG_TIDY "${CLANG_TIDY_TEST}")
endif()
##############################
# Post-Build Steps
##############################
# Copy testing plugins
add_custom_command(TARGET libloot_internals_tests POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${testing-plugins_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}/testing-plugins)
add_custom_command(TARGET libloot_tests POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${testing-plugins_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}/testing-plugins)
+121
View File
@@ -0,0 +1,121 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2013-2016 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<https://www.gnu.org/licenses/>.
*/
#ifndef LOOT_API_H
#define LOOT_API_H
#include <filesystem>
#include <functional>
#include <memory>
#include <string>
#include <string_view>
#include "loot/api_decorator.h"
#include "loot/enum/game_type.h"
#include "loot/enum/log_level.h"
#include "loot/exception/cyclic_interaction_error.h"
#include "loot/exception/plugin_not_loaded_error.h"
#include "loot/exception/undefined_group_error.h"
#include "loot/game_interface.h"
#include "loot/loot_version.h"
namespace loot {
/**
* @name Logging Functions
* @{
*/
/**
* @brief Set the callback function that is called when logging.
* @param callback
* The function called when logging. The first parameter is the
* level of the message being logged, and the second is the message.
*/
LOOT_API void SetLoggingCallback(
std::function<void(LogLevel, std::string_view)> callback);
/**
* @brief Set the log severity level.
* @details The default level setting is trace. This function has no effect if
* no logging callback has been set.
* @param level
* Messages of this severity level and higher will be logged.
*/
LOOT_API void SetLogLevel(LogLevel level);
/**
* @}
* @name Version Functions
* @{
*/
/**
* @brief Checks for API compatibility.
* @details Checks whether the loaded API is compatible with the given
* version of the API, abstracting API stability policy away from
* clients. The version numbering used is major.minor.patch.
* @param major
* The major version number to check.
* @param minor
* The minor version number to check.
* @param patch
* The patch version number to check.
* @returns True if the API versions are compatible, false otherwise.
*/
LOOT_API bool IsCompatible(const unsigned int major,
const unsigned int minor,
const unsigned int patch);
/**
* @}
* @name Lifecycle Management Functions
* @{
*/
/**
* @brief Initialise a new game handle.
* @details Creates a handle for a game, which is then used by all
* game-specific functions.
* @param game
* A game code for which to create the handle.
* @param game_path
* The relative or absolute path to the directory containing the
* game's executable.
* @param game_local_path
* The relative or absolute path to the game's local data folder, or an
* empty path. The local data folder is usually in `%%LOCALAPPDATA%`, but
* Morrowind has no local data folder and OpenMW's is in the user's
* My Games folder on Windows and in `$HOME/.config` on Linux. If an
* empty path is provided, the API will attempt to look up the relevant
* local data path, which may fail in some situations (e.g. when running
* libloot natively on Linux for a game other than Morrowind or OpenMW).
* @returns The new game handle.
*/
LOOT_API std::unique_ptr<GameInterface> CreateGameHandle(
const GameType game,
const std::filesystem::path& game_path,
const std::filesystem::path& game_local_path = "");
}
#endif
+44
View File
@@ -0,0 +1,44 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2013-2016 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<https://www.gnu.org/licenses/>.
*/
#ifndef LOOT_API_DECORATOR
#define LOOT_API_DECORATOR
/* set up dll import/export decorators
when compiling the dll on windows, ensure LOOT_EXPORT is defined. clients
that use this header do not need to define anything to import the symbols
properly. */
#if defined(_WIN32)
#ifdef LOOT_STATIC
#define LOOT_API
#elif defined LOOT_EXPORT
#define LOOT_API __declspec(dllexport)
#else
#define LOOT_API __declspec(dllimport)
#endif
#else
#define LOOT_API
#endif
#endif
+257
View File
@@ -0,0 +1,257 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2012-2016 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<https://www.gnu.org/licenses/>.
*/
#ifndef LOOT_DATABASE_INTERFACE
#define LOOT_DATABASE_INTERFACE
#include <filesystem>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
#include "loot/exception/cyclic_interaction_error.h"
#include "loot/metadata/group.h"
#include "loot/metadata/message.h"
#include "loot/metadata/plugin_metadata.h"
namespace loot {
/** @brief The interface provided by API's database handle. */
class DatabaseInterface {
public:
virtual ~DatabaseInterface() = default;
/**
* @name Data Reading & Writing
* @{
*/
/**
* @brief Loads the masterlist from the path specified.
* @details Can be called multiple times, each time replacing the
* previously-loaded data.
* @param masterlistPath
* The relative or absolute path to the masterlist file that should be
* loaded.
*/
virtual void LoadMasterlist(
const std::filesystem::path& masterlistPath) = 0;
/**
* @brief Loads the masterlist and masterlist prelude from the paths
specified.
* @details Can be called multiple times, each time replacing the
* previously-loaded data.
* @param masterlistPath
* The relative or absolute path to the masterlist file that should be
* loaded.
* @param masterlistPreludePath
* The relative or absolute path to the masterlist prelude file that
* should be loaded.
*/
virtual void LoadMasterlistWithPrelude(
const std::filesystem::path& masterlistPath,
const std::filesystem::path& masterlistPreludePath) = 0;
/**
* @brief Loads the userlist from the path specified.
* @details Can be called multiple times, each time replacing the
* previously-loaded data.
* @param userlistPath
* The relative or absolute path to the userlist file that should be
* loaded.
*/
virtual void LoadUserlist(const std::filesystem::path& userlistPath) = 0;
/**
* Writes a metadata file containing all loaded user-added metadata.
* @param outputFile
* The path to which the file shall be written.
* @param overwrite
* If `false` and `outputFile` already exists, no data will be
* written. Otherwise, data will be written.
*/
virtual void WriteUserMetadata(const std::filesystem::path& outputFile,
const bool overwrite) const = 0;
/**
* @brief Writes a minimal metadata file that only contains plugins with
* Bash Tag suggestions and/or dirty info, plus the suggestions and
* info themselves.
* @param outputFile
* The path to which the file shall be written.
* @param overwrite
* If `false` and `outputFile` already exists, no data will be
* written. Otherwise, data will be written.
*/
virtual void WriteMinimalList(const std::filesystem::path& outputFile,
const bool overwrite) const = 0;
/**
* @brief Evaluate the given condition string.
* @param condition A condition string.
*/
virtual bool Evaluate(const std::string& condition) const = 0;
/**
* @}
* @name Non-plugin Data Access
* @{
*/
/**
* @brief Gets the Bash Tags that are listed in the loaded metadata lists.
* @details Bash Tag suggestions can include Bash Tags not in this list.
* @returns A set of Bash Tag names.
*/
virtual std::vector<std::string> GetKnownBashTags() const = 0;
/**
* @brief Get all general messages listen in the loaded metadata lists.
* @param evaluateConditions
* If true, any metadata conditions are evaluated before the metadata
* is returned, otherwise unevaluated metadata is returned. Evaluating
* general message conditions also clears the condition cache before
* evaluating conditions.
* @returns A vector of messages supplied in the metadata lists but not
* attached to any particular plugin.
*/
virtual std::vector<Message> GetGeneralMessages(
bool evaluateConditions = false) const = 0;
/**
* @brief Gets the groups that are defined in the loaded metadata lists.
* @param includeUserMetadata
* If true, any group metadata present in the userlist is included in
* the returned metadata, otherwise the metadata returned only includes
* metadata from the masterlist.
* @returns An vector of Group objects. Each Group's name is unique, if a
* group has masterlist and user metadata the two are merged into a
* single group object.
*/
virtual std::vector<Group> GetGroups(
bool includeUserMetadata = true) const = 0;
/**
* @brief Gets the groups that are defined or extended in the loaded userlist.
* @returns An unordered set of Group objects.
*/
virtual std::vector<Group> GetUserGroups() const = 0;
/**
* @brief Sets the group definitions to store in the userlist, overwriting any
* existing definitions there.
* @param groups
* The unordered set of Group objects to set.
*/
virtual void SetUserGroups(const std::vector<Group>& groups) = 0;
/**
* @brief Get the "shortest" path between the two given groups according to
* their load after metadata.
* @details The "shortest" path is defined as the path that maximises the
* amount of user metadata involved while minimising the amount of
* masterlist metadata involved. It's not the path involving the
* fewest groups.
* @param fromGroupName
* The name of the source group, that loads earlier.
* @param toGroupName
* The name of the destination group, that loads later.
* @returns A vector of Vertex elements representing the path from the source
* group to the destination group, or an empty vector if no path
* exists.
*/
virtual std::vector<Vertex> GetGroupsPath(
std::string_view fromGroupName,
std::string_view toGroupName) const = 0;
/**
* @}
* @name Plugin Data Access
* @{
*/
/**
* @brief Get all a plugin's loaded metadata.
* @param plugin
* The filename of the plugin to look up metadata for.
* @param includeUserMetadata
* If true, any user metadata the plugin has is included in the
* returned metadata, otherwise the metadata returned only includes
* metadata from the masterlist.
* @param evaluateConditions
* If true, any metadata conditions are evaluated before the metadata
* is returned, otherwise unevaluated metadata is returned. Evaluating
* plugin metadata conditions does not clear the condition cache.
* @returns If the plugin has metadata, an optional containing that metadata,
* otherwise an optional containing no value.
*/
virtual std::optional<PluginMetadata> GetPluginMetadata(
std::string_view plugin,
bool includeUserMetadata = true,
bool evaluateConditions = false) const = 0;
/**
* @brief Get a plugin's metadata loaded from the given userlist.
* @param plugin
* The filename of the plugin to look up user-added metadata for.
* @param evaluateConditions
* If true, any metadata conditions are evaluated before the metadata
* is returned, otherwise unevaluated metadata is returned. Evaluating
* plugin metadata conditions does not clear the condition cache.
* @returns If the plugin has user-added metadata, an optional containing
* that metadata, otherwise an optional containing no value.
*/
virtual std::optional<PluginMetadata> GetPluginUserMetadata(
std::string_view plugin,
bool evaluateConditions = false) const = 0;
/**
* @brief Sets a plugin's user metadata, overwriting any existing user
* metadata.
* @param pluginMetadata
* The user metadata you want to set, with plugin.Name() being the
* filename of the plugin the metadata is for.
*/
virtual void SetPluginUserMetadata(const PluginMetadata& pluginMetadata) = 0;
/**
* @brief Discards all loaded user metadata for the plugin with the given
* filename.
* @param plugin
* The filename of the plugin for which all user-added metadata
* should be deleted.
*/
virtual void DiscardPluginUserMetadata(std::string_view plugin) = 0;
/**
* @brief Discards all loaded user metadata for all plugins, and any
* user-added general messages and known bash tags.
*/
virtual void DiscardAllUserMetadata() = 0;
/** @} */
};
}
#endif
+53
View File
@@ -0,0 +1,53 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2012-2016 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<https://www.gnu.org/licenses/>.
*/
#ifndef LOOT_EDGE_TYPE
#define LOOT_EDGE_TYPE
/**
* The namespace used by libloot.
*/
namespace loot {
/**
* @brief An enum representing the different possible types of interactions
* between plugins or groups.
*/
enum struct EdgeType : unsigned int {
hardcoded,
masterFlag,
master,
masterlistRequirement,
userRequirement,
masterlistLoadAfter,
userLoadAfter,
masterlistGroup,
userGroup,
recordOverlap,
assetOverlap,
tieBreak,
blueprintMaster,
};
}
#endif
+61
View File
@@ -0,0 +1,61 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2012-2016 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<https://www.gnu.org/licenses/>.
*/
#ifndef LOOT_GAME_TYPE
#define LOOT_GAME_TYPE
/**
* The namespace used by libloot.
*/
namespace loot {
/** @brief Codes used to create database handles for specific games. */
enum struct GameType : unsigned int {
/** The Elder Scrolls IV: Oblivion */
tes4,
/** The Elder Scrolls V: Skyrim */
tes5,
/** Fallout 3 */
fo3,
/** Fallout: New Vegas */
fonv,
/** Fallout 4 */
fo4,
/** The Elder Scrolls V: Skyrim Special Edition */
tes5se,
/** Fallout 4 VR */
fo4vr,
/** Skyrim VR */
tes5vr,
/** The Elder Scrolls III: Morrowind */
tes3,
/** Starfield */
starfield,
/** OpenMW */
openmw,
/** The Elder Scrolls IV: Oblivion Remastered */
oblivionRemastered
};
}
#endif
+44
View File
@@ -0,0 +1,44 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2012-2016 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<https://www.gnu.org/licenses/>.
*/
#ifndef LOOT_LOG_LEVEL
#define LOOT_LOG_LEVEL
/**
* The namespace used by libloot.
*/
namespace loot {
/**
* @brief Codes used to specify different levels of API logging.
*/
enum struct LogLevel : unsigned int {
trace,
debug,
info,
warning,
error
};
}
#endif
+49
View File
@@ -0,0 +1,49 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2012-2016 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<https://www.gnu.org/licenses/>.
*/
#ifndef LOOT_MESSAGE_TYPE
#define LOOT_MESSAGE_TYPE
/**
* The namespace used by libloot.
*/
namespace loot {
/** @brief Codes used to indicate the type of a message. */
enum struct MessageType : unsigned int {
/** A notification message that is of no significant severity. */
say,
/**
* A warning message, used to indicate that an issue may be present that the
* user may wish to act on.
*/
warn,
/**
* An error message, used to indicate that an issue that requires user action
* is present.
*/
error,
};
}
#endif
@@ -0,0 +1,61 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2012-2016 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<https://www.gnu.org/licenses/>.
*/
#ifndef LOOT_EXCEPTION_CYCLIC_INTERACTION_ERROR
#define LOOT_EXCEPTION_CYCLIC_INTERACTION_ERROR
#include <stdexcept>
#include <vector>
#include "loot/api_decorator.h"
#include "loot/vertex.h"
namespace loot {
/**
* @brief An exception class thrown if a cyclic interaction is detected when
* sorting a load order.
*/
class CyclicInteractionError : public std::runtime_error {
public:
/**
* @brief Construct an exception detailing a plugin or group graph cycle.
* @param cycle A representation of the cyclic path.
*/
LOOT_API CyclicInteractionError(std::vector<Vertex> cycle);
/**
* @brief Get a representation of the cyclic path.
* @details Each Vertex is the name of a graph element (plugin or group) and
* the type of the edge going to the next Vertex. The last Vertex
* has an edge going to the first Vertex.
* @return A vector of Vertex elements representing the cyclic path.
*/
LOOT_API std::vector<Vertex> GetCycle() const;
private:
std::vector<Vertex> cycle_;
};
}
#endif
@@ -0,0 +1,41 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2012-2016 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<https://www.gnu.org/licenses/>.
*/
#ifndef LOOT_EXCEPTION_PLUGIN_NOT_LOADED_ERROR
#define LOOT_EXCEPTION_PLUGIN_NOT_LOADED_ERROR
#include <stdexcept>
namespace loot {
/**
* @brief An exception class thrown if a plugin that must be loaded hasn't been
* loaded.
*/
class PluginNotLoadedError : public std::runtime_error {
public:
using std::runtime_error::runtime_error;
};
}
#endif
@@ -0,0 +1,56 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2012-2016 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<https://www.gnu.org/licenses/>.
*/
#ifndef LOOT_EXCEPTION_UNDEFINED_GROUP_ERROR
#define LOOT_EXCEPTION_UNDEFINED_GROUP_ERROR
#include <stdexcept>
#include <string_view>
#include "loot/api_decorator.h"
namespace loot {
/**
* @brief An exception class thrown if group is referenced but is undefined.
*/
class UndefinedGroupError : public std::runtime_error {
public:
/**
* @brief Construct an exception for an undefined group.
* @param groupName The name of the group that is undefined.
*/
LOOT_API UndefinedGroupError(std::string_view groupName);
/**
* Get the name of the undefined group.
* @return A group name.
*/
LOOT_API std::string GetGroupName() const;
private:
std::string groupName_;
};
}
#endif
+243
View File
@@ -0,0 +1,243 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2012-2016 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<https://www.gnu.org/licenses/>.
*/
#ifndef LOOT_GAME_INTERFACE
#define LOOT_GAME_INTERFACE
#include "loot/database_interface.h"
#include "loot/enum/game_type.h"
#include "loot/plugin_interface.h"
namespace loot {
/** @brief The interface provided for accessing game-specific functionality. */
class GameInterface {
public:
virtual ~GameInterface() = default;
/**
* @brief Get the game's type.
* @returns The game's type.
*/
virtual GameType GetType() const = 0;
/**
* @brief Gets the currently-set additional data paths.
* @details The following games are configured with additional data paths by
* default:
* - Fallout 4, when installed from the Microsoft Store
* - Starfield
* - OpenMW
*/
virtual std::vector<std::filesystem::path> GetAdditionalDataPaths() const = 0;
/**
* @brief Set additional data paths.
* @details The additional data paths are used when interacting with the load
* order, evaluating conditions and scanning for archives (BSA/BA2
* depending on the game). Additional data paths are used in the
* order they are given (except with OpenMW, which checks them in
* reverse order), and take precedence over the game's main data
* path.
*/
virtual void SetAdditionalDataPaths(
const std::vector<std::filesystem::path>& additionalDataPaths) = 0;
/**
* @name Metadata Access
* @{
*/
/**
* @brief Get the database interface used for accessing metadata-related
* functionality.
* @returns A reference to the game's DatabaseInterface. The reference remains
* valid for the lifetime of the GameInterface instance.
*/
virtual DatabaseInterface& GetDatabase() = 0;
/**
* @brief Get the database interface used for accessing metadata-related
* functionality.
* @returns A reference to the game's DatabaseInterface. The reference remains
* valid for the lifetime of the GameInterface instance.
*/
virtual const DatabaseInterface& GetDatabase() const = 0;
/**
* @}
* @name Plugin Data Access
* @{
*/
/**
* @brief Check if a file is a valid plugin.
* @details The validity check is not exhaustive: it generally checks that the
* file is a valid plugin file extension for the game and that its
* header (if applicable) can be parsed.
* @param pluginPath
* The path to the file to check. Relative paths are resolved relative
* to the game's plugins directory, while absolute paths are used
* as given.
* @returns True if the file is a valid plugin, false otherwise.
*/
virtual bool IsValidPlugin(const std::filesystem::path& pluginPath) const = 0;
/**
* @brief Parses plugins and loads their data.
* @details If a given plugin filename (or one that is case-insensitively
* equal) has already been loaded, its previously-loaded data
* data is discarded, invalidating any existing shared pointers to
* that plugin's PluginInterface object.
*
* If the game is Morrowind, OpenMW or Starfield, it's only valid to
* fully load a plugin if its masters are already loaded or included
* in the same input vector.
* @param pluginPaths
* The plugin paths to load. Relative paths are resolved relative to
* the game's plugins directory, while absolute paths are used as
* given. Each plugin filename must be unique within the vector.
* @param loadHeadersOnly
* If true, only the plugins' headers are loaded. If false, all records
* in the plugins are parsed.
*/
virtual void LoadPlugins(
const std::vector<std::filesystem::path>& pluginPaths,
bool loadHeadersOnly) = 0;
/**
* @brief Clears the plugins loaded by previous calls to `LoadPlugins()`.
* @details This invalidates any PluginInterface pointers retrieved using
* `GetPlugin()` or `GetLoadedPlugins()`.
*/
virtual void ClearLoadedPlugins() = 0;
/**
* @brief Get data for a loaded plugin.
* @param pluginName
* The filename of the plugin to get data for.
* @returns A shared pointer to a const PluginInterface implementation. The
* pointer is null if the given plugin has not been loaded. The
* pointer remains valid until the `ClearLoadedPlugins()` function
* is called, this GameInterface is destroyed, or until a plugin with
* a case-insensitively equal filename is loaded.
*/
virtual std::shared_ptr<const PluginInterface> GetPlugin(
std::string_view pluginName) const = 0;
/**
* @brief Get a set of const references to all loaded plugins' PluginInterface
* objects.
* @returns A set of shared pointers to const PluginInterface. The pointers
* remain valid until the `ClearLoadedPlugins()` function is called,
* this GameInterface is destroyed, or until a plugin with a
* case-insensitively equal filename is loaded.
*/
virtual std::vector<std::shared_ptr<const PluginInterface>> GetLoadedPlugins()
const = 0;
/**
* @}
* @name Sorting
* @{
*/
/**
* @brief Calculates a new load order for the game's installed plugins
* (including inactive plugins) and outputs the sorted order.
* @details Pulls metadata from the masterlist and userlist if they are
* loaded, and reads the contents of each plugin. No changes are
* applied to the load order used by the game. This function does
* not load or evaluate the masterlist or userlist.
* @param pluginFilenames
* The plugins to sort, in their current load order. All given plugins
* must have been loaded using `LoadPlugins()`.
* @returns A vector of the given plugin filenames in their sorted load
* order.
*/
virtual std::vector<std::string> SortPlugins(
const std::vector<std::string>& pluginFilenames) = 0;
/**
* @}
* @name Load Order Interaction
* @{
*/
/**
*
* @brief Load the current load order state, discarding any previously held
* state.
* @details This function should be called whenever the load order or active
* state of plugins "on disk" changes, so that the cached state is
* updated to reflect the changes.
*/
virtual void LoadCurrentLoadOrderState() = 0;
/**
* @brief Check if the load order is ambiguous.
* @details This checks that all plugins in the current load order state have
* a well-defined position in the "on disk" state, and that all data
* sources are consistent. If the load order is ambiguous, different
* applications may read different load orders from the same source
* data.
* @returns True if the load order is ambiguous, false otherwise.
*/
virtual bool IsLoadOrderAmbiguous() const = 0;
/**
* @brief Gets the path to the file that holds the list of active plugins.
* @details The active plugins file path is often within the game's local
path, but its name and location varies by game and game
configuration, so this function exposes the path that libloot
uses.
* @returns The file path.
*/
virtual std::filesystem::path GetActivePluginsFilePath() const = 0;
/**
* @brief Check if a plugin is active.
* @param plugin
* The filename of the plugin for which to check the active state.
* @returns True if the plugin is active, false otherwise.
*/
virtual bool IsPluginActive(const std::string& plugin) const = 0;
/**
* @brief Get the current load order.
* @returns A vector of plugin filenames in their load order.
*/
virtual std::vector<std::string> GetLoadOrder() const = 0;
/**
* @brief Set the game's load order.
* @details There is no way to persist the load order of inactive OpenMW
* plugins, so setting an OpenMW load order will have no effect if
* the relative order of active plugins is unchanged.
* @param loadOrder
* A vector of plugin filenames sorted in the load order to set.
*/
virtual void SetLoadOrder(const std::vector<std::string>& loadOrder) = 0;
};
}
#endif

Some files were not shown because too many files have changed in this diff Show More