diff --git a/extension/doc_classes/GameSingleton.xml b/extension/doc_classes/GameSingleton.xml
index ef492e01..bd00d187 100644
--- a/extension/doc_classes/GameSingleton.xml
+++ b/extension/doc_classes/GameSingleton.xml
@@ -89,6 +89,15 @@
Returns the localization key [String] of the mapmode with the specified [param index].
+
+
+
+ Returns an [Array] of [Dictionary] containing information about available mods, with each [Dictionary] containing values for the following [StringName] keys:
+ - [code]"identifier"[/code] - The mod's [String] name
+ - [code]"dependencies"[/code] - A [PackedStringArray] of dependency mod names
+ - [code]"is_loaded"[/code] - Is [code]true[/code] if the mod is a currently loaded mod, else [code]false[/code]
+
+
@@ -153,8 +162,10 @@
+
- Load compatibility mode text defines, localization string and map and flag images. Returns [code]FAILED[/code] if there are any problems when loading all this data, otherwise returns [code]OK[/code].
+ Load compatibility mode text defines, localization string and map and flag images, loading data from [param mods] if not empty. Returns [code]FAILED[/code] if there are any problems when loading all this data, otherwise returns [code]OK[/code].
+ See [method get_mod_info] for a valid list of values.
@@ -173,10 +184,9 @@
-
-
+
- Set the dataloading roots to those provided in [param file_paths], ignoring the filepaths in [param replace_paths] in favor of mods, which should contain full filepaths to the base game's installation and to any mods that are to be loaded on top of it. Returns [code]FAILED[/code] if there are any problems when setting the dataloading roots, otherwise returns [code]OK[/code].
+ Set the dataloading roots to those provided in [param path] which should contain full filepaths to the base game's installation and where the search for mods will begin from. Returns [code]FAILED[/code] if there are any problems when setting the dataloading roots, otherwise returns [code]OK[/code].
diff --git a/extension/src/openvic-extension/singletons/GameSingleton.cpp b/extension/src/openvic-extension/singletons/GameSingleton.cpp
index f24c4c67..42df09a0 100644
--- a/extension/src/openvic-extension/singletons/GameSingleton.cpp
+++ b/extension/src/openvic-extension/singletons/GameSingleton.cpp
@@ -4,8 +4,10 @@
#include
#include
+#include
#include
+#include
#include
#include
@@ -16,6 +18,8 @@
#include "openvic-extension/core/Bind.hpp"
#include "openvic-extension/utility/Utilities.hpp"
+#include
+
#include
#include
@@ -39,12 +43,14 @@ StringName const& GameSingleton::_signal_mapmode_changed() {
void GameSingleton::_bind_methods() {
OV_BIND_SMETHOD(setup_logger);
- OV_BIND_METHOD(GameSingleton::load_defines_compatibility_mode);
- OV_BIND_METHOD(GameSingleton::set_compatibility_mode_roots, { "file_paths", "replace_paths" }, DEFVAL(PackedStringArray{}));
+ OV_BIND_METHOD(GameSingleton::load_defines_compatibility_mode, { "mods" }, DEFVAL(PackedStringArray()));
+ OV_BIND_METHOD(GameSingleton::set_compatibility_mode_roots, { "path" });
OV_BIND_SMETHOD(search_for_game_path, { "hint_path" }, DEFVAL(String {}));
OV_BIND_METHOD(GameSingleton::lookup_file_path, { "path" });
+ OV_BIND_METHOD(GameSingleton::get_mod_info);
+
OV_BIND_METHOD(GameSingleton::get_bookmark_info);
OV_BIND_METHOD(GameSingleton::setup_game, { "bookmark_index" });
OV_BIND_METHOD(GameSingleton::is_game_instance_setup);
@@ -143,6 +149,37 @@ void GameSingleton::setup_logger() {
spdlog::default_logger_raw()->sinks().push_back(std::move(godot_sink));
}
+TypedArray GameSingleton::get_mod_info() const {
+ static const StringName identifier_key = "identifier";
+ static const StringName dependencies_key = "dependencies";
+ static const StringName is_loaded_key = "is_loaded";
+
+ TypedArray results;
+
+ ModManager const& mod_manager = game_manager.get_mod_manager();
+ memory::vector const& loaded_mods = mod_manager.get_loaded_mods();
+
+ for (Mod const& mod : mod_manager.get_mods()) {
+ Dictionary mod_info_dictionary;
+
+ mod_info_dictionary[identifier_key] = Utilities::std_to_godot_string(mod.get_identifier());
+
+ mod_info_dictionary[dependencies_key] = [&]() -> PackedStringArray {
+ PackedStringArray result;
+ for (std::string_view dep_id : mod.get_dependencies()) {
+ result.push_back(Utilities::std_to_godot_string(dep_id));
+ }
+ return result;
+ }();
+
+ mod_info_dictionary[is_loaded_key] = ranges::contains(loaded_mods, &mod);
+
+ results.push_back(std::move(mod_info_dictionary));
+ }
+
+ return results;
+}
+
TypedArray GameSingleton::get_bookmark_info() const {
static const StringName bookmark_info_name_key = "bookmark_name";
static const StringName bookmark_info_date_key = "bookmark_date";
@@ -662,30 +699,26 @@ Error GameSingleton::_load_flag_sheet() {
return ret;
}
-Error GameSingleton::set_compatibility_mode_roots(
- PackedStringArray const& file_paths, godot::PackedStringArray const& replace_paths
-) {
- Dataloader::path_vector_t roots;
- roots.reserve(file_paths.size());
- for (String const& path : file_paths) {
- roots.emplace_back(Utilities::godot_to_std_string(path));
- }
-
- // TODO @BrickPI https://github.com/OpenVicProject/OpenVic/pull/512
- // Dataloader::path_vector_t replace;
- // replace.reserve(replace_paths.size());
- // for (String const& path : replace_paths) {
- // replace.emplace_back(Utilities::godot_to_std_string(path));
- // }
-
+Error GameSingleton::set_compatibility_mode_roots(String const& path) {
+ Dataloader::path_vector_t roots { Utilities::godot_to_std_string(path) };
ERR_FAIL_COND_V_MSG(!game_manager.set_base_path(roots), FAILED, "Failed to set dataloader roots!");
return OK;
}
-Error GameSingleton::load_defines_compatibility_mode() {
+Error GameSingleton::load_defines_compatibility_mode(PackedStringArray const& mods) {
Error err = OK;
auto add_message = std::bind_front(&LoadLocalisation::add_message, LoadLocalisation::get_singleton());
+ ERR_FAIL_COND_V_MSG(!game_manager.load_mod_descriptors(), FAILED, "Failed to load mod descriptors!");
+
+ memory::vector std_mods;
+ std_mods.reserve(mods.size());
+ for (String const& mod : mods) {
+ std_mods.emplace_back(Utilities::godot_to_std_string(mod));
+ }
+
+ ERR_FAIL_COND_V_MSG(!game_manager.load_mods(std_mods), FAILED, "Loading mods failed.");
+
if (!game_manager.load_definitions(add_message)) {
UtilityFunctions::push_error("Failed to load defines!");
err = FAILED;
diff --git a/extension/src/openvic-extension/singletons/GameSingleton.hpp b/extension/src/openvic-extension/singletons/GameSingleton.hpp
index 28b18871..167124b9 100644
--- a/extension/src/openvic-extension/singletons/GameSingleton.hpp
+++ b/extension/src/openvic-extension/singletons/GameSingleton.hpp
@@ -2,6 +2,7 @@
#include
#include
+#include
#include
#include
@@ -66,14 +67,14 @@ namespace OpenVic {
/* Load the game's defines in compatibility mode from the filepath
* pointing to the defines folder. */
- godot::Error set_compatibility_mode_roots(
- godot::PackedStringArray const& file_paths, godot::PackedStringArray const& replace_paths = {}
- );
- godot::Error load_defines_compatibility_mode();
+ godot::Error set_compatibility_mode_roots(godot::String const& path);
+ godot::Error load_defines_compatibility_mode(godot::PackedStringArray const& mods = {});
static godot::String search_for_game_path(godot::String const& hint_path = {});
godot::String lookup_file_path(godot::String const& path) const;
+ godot::TypedArray get_mod_info() const;
+
godot::TypedArray get_bookmark_info() const;
/* After initial load or resigning a previous session game setup, all mutable components of the simulation
diff --git a/game/src/Systems/Startup/GameStart.gd b/game/src/Systems/Startup/GameStart.gd
index 329d697d..d9e408e8 100644
--- a/game/src/Systems/Startup/GameStart.gd
+++ b/game/src/Systems/Startup/GameStart.gd
@@ -13,7 +13,7 @@ const GameMenuScene := preload("res://src/UI/GameMenu/GameMenu/GameMenu.tscn")
@export var setting_name : String = "base_defines_path"
var _settings_base_path : String = ""
-var _compatibility_path_list : PackedStringArray = []
+var _mod_list : PackedStringArray = []
var _vic2_settings : GameSettings
func _enter_tree() -> void:
@@ -115,21 +115,22 @@ func _setup_compatibility_mode_paths() -> void:
_vic2_settings.set_value(section_name, setting_name, actual_base_path)
_vic2_settings.emit_changed()
- _compatibility_path_list = [actual_base_path]
-
# Add mod paths
- var settings_mod_names : PackedStringArray = ArgumentParser.get_option_value(&"mod")
- for mod_name : String in settings_mod_names:
- _compatibility_path_list.push_back(actual_base_path + "/mod/" + mod_name)
+ var mod_status_file := ConfigFile.new()
+ mod_status_file.load("user://mods.cfg")
+ _mod_list = mod_status_file.get_value("mods", "load_list", [])
+ for mod in ArgumentParser.get_option_value(&"mod"):
+ if mod not in _mod_list and mod != "":
+ _mod_list.push_back(mod)
func _load_compatibility_mode() -> void:
- if GameSingleton.set_compatibility_mode_roots(_compatibility_path_list) != OK:
+ if GameSingleton.set_compatibility_mode_roots(_settings_base_path) != OK:
push_error("Errors setting game roots!")
CursorManager.initial_cursor_setup()
setup_title_theme()
- if GameSingleton.load_defines_compatibility_mode() != OK:
+ if GameSingleton.load_defines_compatibility_mode(_mod_list) != OK:
push_error("Errors loading game defines!")
SoundSingleton.load_sounds()