Skip to content
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
18 changes: 14 additions & 4 deletions extension/doc_classes/GameSingleton.xml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,15 @@
Returns the localization key [String] of the mapmode with the specified [param index].
</description>
</method>
<method name="get_mod_info" qualifiers="const">
<return type="Dictionary[]" />
<description>
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]
</description>
</method>
<method name="get_province_colour_texture" qualifiers="const">
<return type="ImageTexture" />
<description>
Expand Down Expand Up @@ -153,8 +162,10 @@
</method>
<method name="load_defines_compatibility_mode">
<return type="int" enum="Error" />
<param index="0" name="mods" type="PackedStringArray" default="PackedStringArray()" />
<description>
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.
</description>
</method>
<method name="lookup_file_path" qualifiers="const">
Expand All @@ -173,10 +184,9 @@
</method>
<method name="set_compatibility_mode_roots">
<return type="int" enum="Error" />
<param index="0" name="file_paths" type="PackedStringArray" />
<param index="1" name="replace_paths" type="PackedStringArray" default="PackedStringArray()" />
<param index="0" name="path" type="String" />
<description>
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].
</description>
</method>
<method name="set_mapmode">
Expand Down
71 changes: 52 additions & 19 deletions extension/src/openvic-extension/singletons/GameSingleton.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

#include <godot_cpp/classes/time.hpp>
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/variant/packed_string_array.hpp>
#include <godot_cpp/variant/utility_functions.hpp>

#include <openvic-simulation/dataloader/ModManager.hpp>
#include <openvic-simulation/utility/Containers.hpp>
#include <openvic-simulation/utility/Logger.hpp>

Expand All @@ -16,6 +18,8 @@
#include "openvic-extension/core/Bind.hpp"
#include "openvic-extension/utility/Utilities.hpp"

#include <range/v3/algorithm/contains.hpp>

#include <spdlog/spdlog.h>
#include <spdlog/sinks/callback_sink.h>

Expand All @@ -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);
Expand Down Expand Up @@ -143,6 +149,37 @@ void GameSingleton::setup_logger() {
spdlog::default_logger_raw()->sinks().push_back(std::move(godot_sink));
}

TypedArray<Dictionary> 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<Dictionary> results;

ModManager const& mod_manager = game_manager.get_mod_manager();
memory::vector<Mod const*> 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<Dictionary> GameSingleton::get_bookmark_info() const {
static const StringName bookmark_info_name_key = "bookmark_name";
static const StringName bookmark_info_date_key = "bookmark_date";
Expand Down Expand Up @@ -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<memory::string> 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;
Expand Down
9 changes: 5 additions & 4 deletions extension/src/openvic-extension/singletons/GameSingleton.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <godot_cpp/classes/image_texture.hpp>
#include <godot_cpp/classes/texture2d_array.hpp>
#include <godot_cpp/variant/packed_string_array.hpp>

#include <openvic-simulation/GameManager.hpp>
#include <openvic-simulation/dataloader/Dataloader.hpp>
Expand Down Expand Up @@ -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<godot::Dictionary> get_mod_info() const;

godot::TypedArray<godot::Dictionary> get_bookmark_info() const;

/* After initial load or resigning a previous session game setup, all mutable components of the simulation
Expand Down
17 changes: 9 additions & 8 deletions game/src/Systems/Startup/GameStart.gd
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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()
Expand Down
Loading