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
19 changes: 10 additions & 9 deletions src/openvic-simulation/GameManager.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "GameManager.hpp"

#include <chrono>
#include <functional>
#include <string_view>

#include <range/v3/algorithm/contains.hpp>
Expand Down Expand Up @@ -76,7 +77,7 @@ bool GameManager::load_mods(memory::vector<memory::string> const& mods_to_find)

bool ret = true;

vector_ordered_set<Mod const*> load_list;
vector_ordered_set<std::reference_wrapper<const Mod>> load_list;

/* Check loaded mod descriptors for requested mods, using either full name or user directory name
* (Historical Project Mod 0.4.6 or HPM both valid, for example), and load them plus their dependencies.
Expand All @@ -94,8 +95,8 @@ bool GameManager::load_mods(memory::vector<memory::string> const& mods_to_find)
continue;
}

Mod const* mod_ptr = &*it;
vector_ordered_set<Mod const*> dependencies = mod_ptr->generate_dependency_list(&ret);
Mod const& mod = *it;
vector_ordered_set<std::reference_wrapper<const Mod>> dependencies = mod.generate_dependency_list(&ret);
if(!ret) {
continue;
}
Expand All @@ -104,15 +105,15 @@ bool GameManager::load_mods(memory::vector<memory::string> const& mods_to_find)
if (load_list.empty()) {
load_list = std::move(dependencies);
} else {
for (Mod const* dep : dependencies) {
for (Mod const& dep : dependencies) {
if (!load_list.contains(dep)) {
load_list.emplace(dep);
}
}
}

if (!load_list.contains(mod_ptr)) {
load_list.emplace(mod_ptr);
if (!load_list.contains(mod)) {
load_list.emplace(mod);
}
}

Expand All @@ -122,9 +123,9 @@ bool GameManager::load_mods(memory::vector<memory::string> const& mods_to_find)
vector_ordered_set<fs::path> replace_paths;

/* Actually registers all roots and replace paths to be loaded by the game. */
for (Mod const* mod : load_list) {
roots.emplace_back(roots[0] / mod->get_dataloader_root_path());
for (std::string_view path : mod->get_replace_paths()) {
for (Mod const& mod : load_list) {
roots.emplace_back(roots[0] / mod.get_dataloader_root_path());
for (std::string_view path : mod.get_replace_paths()) {
replace_paths.emplace(path);
}
}
Expand Down
36 changes: 19 additions & 17 deletions src/openvic-simulation/dataloader/ModManager.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#include "ModManager.hpp"

#include <functional>
#include <string_view>

#include "openvic-simulation/core/error/ErrorMacros.hpp"
#include "openvic-simulation/dataloader/NodeTools.hpp"
#include "openvic-simulation/types/HasIdentifier.hpp"
#include "openvic-simulation/types/IdentifierRegistry.hpp"
#include "openvic-simulation/types/OrderedContainers.hpp"
#include "openvic-simulation/core/FormatValidate.hpp"

using namespace OpenVic;
using namespace OpenVic::NodeTools;
Expand All @@ -27,42 +27,48 @@ Mod::Mod(
replace_paths { new_replace_paths },
dependencies { new_dependencies } {}

vector_ordered_set<Mod const*> Mod::generate_dependency_list(bool* success) const {
vector_ordered_set<std::reference_wrapper<const Mod>> Mod::generate_dependency_list(bool* success) const {
static constexpr size_t MAX_RECURSE = 16;
size_t current_recurse = 0;

vector_ordered_set<Mod const*> result;
vector_ordered_set<std::reference_wrapper<const Mod>> result;

auto dep_cycle = [this, &current_recurse](auto self, Mod const* mod, vector_ordered_set<Mod const*>& dep_list) -> bool {
auto dep_cycle = [this, &current_recurse](
auto self,
Mod const& mod,
vector_ordered_set<std::reference_wrapper<const Mod>>& dep_list
) -> bool {
bool ret = true;
for (std::string_view dep_identifier : mod->get_dependencies()) {
if (!mod_manager.has_mod_identifier(dep_identifier)) {
for (std::string_view dep_identifier : mod.get_dependencies()) {
Mod const* dep_ptr = mod_manager.get_mod_by_identifier(dep_identifier);
if (dep_ptr == nullptr) {
spdlog::error_s(
"Mod \"{}\" has unmet dependency \"{}\" and cannot be loaded!",
ovfmt::validate(mod), dep_identifier
mod, dep_identifier
);
return false;
}
Mod const* dep = mod_manager.get_mod_by_identifier(dep_identifier);
Mod const& dep = *dep_ptr;
/* The poor man's cycle checking (cycles should be very rare and hard to accomplish with vic2 modding, this is a failsafe) */
if (current_recurse == MAX_RECURSE) {
spdlog::error_s(
"Mod \"{}\" has cyclical or broken dependency chain and cannot be loaded!",
ovfmt::validate(mod)
mod
);
return false;
} else {
current_recurse++;
ret &= self(self, dep, dep_list); /* recursively search for mod dependencies */
}

if (!dep_list.contains(dep)) {
dep_list.emplace(dep);
}
}
return ret;
};

bool loaded_deps = dep_cycle(dep_cycle, this, result);
bool loaded_deps = dep_cycle(dep_cycle, *this, result);
if (success) {
*success = loaded_deps;
}
Expand Down Expand Up @@ -100,20 +106,16 @@ bool ModManager::load_mod_file(ast::NodeCPtr root) {
return true;
}

void ModManager::set_loaded_mods(memory::vector<Mod const*>&& new_loaded_mods) {
void ModManager::set_loaded_mods(memory::vector<std::reference_wrapper<const Mod>>&& new_loaded_mods) {
OV_ERR_FAIL_COND_MSG(mods_loaded, "set_loaded_mods called twice");

loaded_mods = std::move(new_loaded_mods);
mods_loaded = true;
for (Mod const* mod : loaded_mods) {
SPDLOG_INFO("Loading mod \"{}\" at path {}", *mod, mod->get_dataloader_root_path());
for (Mod const& mod : loaded_mods) {
SPDLOG_INFO("Loading mod \"{}\" at path {}", mod, mod.get_dataloader_root_path());
}
}

memory::vector<Mod const*> const& ModManager::get_loaded_mods() const {
return loaded_mods;
}

size_t ModManager::get_loaded_mod_count() const {
return loaded_mods.size();
}
9 changes: 5 additions & 4 deletions src/openvic-simulation/dataloader/ModManager.hpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#pragma once

#include <cstddef>
#include <functional>
#include <string_view>

#include "openvic-simulation/types/HasIdentifier.hpp"
#include "openvic-simulation/types/IdentifierRegistry.hpp"
#include "openvic-simulation/dataloader/NodeTools.hpp"
#include "openvic-simulation/utility/Getters.hpp"

namespace OpenVic {
struct ModManager;
Expand All @@ -32,22 +34,21 @@ namespace OpenVic {
);
Mod(Mod&&) = default;

vector_ordered_set<Mod const*> generate_dependency_list(bool* success = nullptr) const;
vector_ordered_set<std::reference_wrapper<const Mod>> generate_dependency_list(bool* success = nullptr) const;
};

struct ModManager {

private:
IdentifierRegistry<Mod> IDENTIFIER_REGISTRY(mod);
memory::vector<Mod const*> loaded_mods;
memory::vector<std::reference_wrapper<const Mod>> SPAN_PROPERTY(loaded_mods);
bool mods_loaded = false;

public:
ModManager();

bool load_mod_file(ast::NodeCPtr root);
void set_loaded_mods(memory::vector<Mod const*>&& new_loaded_mods);
memory::vector<Mod const*> const& get_loaded_mods() const;
void set_loaded_mods(memory::vector<std::reference_wrapper<const Mod>>&& new_loaded_mods);
size_t get_loaded_mod_count() const;
};
}
22 changes: 19 additions & 3 deletions src/openvic-simulation/types/HasIdentifier.hpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#pragma once

#include <algorithm>
#include <cassert>
#include <cstddef>
#include <string_view>
#include <ostream>

#include <fmt/base.h>

#include "openvic-simulation/types/Colour.hpp"
#include "openvic-simulation/core/template/Concepts.hpp"
#include "openvic-simulation/types/Colour.hpp"
#include "openvic-simulation/utility/Getters.hpp"

namespace OpenVic {
Expand All @@ -30,6 +30,12 @@ namespace OpenVic {
HasIdentifier(HasIdentifier&&) = default;
HasIdentifier& operator=(HasIdentifier const&) = delete;
HasIdentifier& operator=(HasIdentifier&&) = delete;

template <std::derived_from<HasIdentifier> T>
requires (!has_index<T>)
friend bool operator==(T const& lhs, T const& rhs) {
return lhs.get_identifier() == rhs.get_identifier();
}
};

inline std::ostream& operator<<(std::ostream& stream, HasIdentifier const& obj) {
Expand Down Expand Up @@ -95,4 +101,14 @@ struct fmt::formatter<T> : fmt::formatter<fmt::string_view> {
fmt::format_context::iterator format(T const& has_id, fmt::format_context& ctx) const {
return fmt::formatter<fmt::string_view>::format(has_id.get_name(), ctx);
}
};
};

namespace std {
template<OpenVic::has_get_identifier T>
requires (!OpenVic::has_index<T>)
struct hash<T> {
[[nodiscard]] std::size_t operator()(T const& obj) const noexcept {
return std::hash<std::string_view>{}(obj.get_identifier());
}
};
}
11 changes: 11 additions & 0 deletions src/openvic-simulation/types/HasIndex.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include <cstddef>

#include <type_safe/strong_typedef.hpp>

#include "openvic-simulation/core/template/Concepts.hpp"
Expand All @@ -26,4 +28,13 @@ namespace OpenVic {
return index == rhs.index;
}
};
}

namespace std {
template<OpenVic::has_index T>
struct hash<T> {
[[nodiscard]] std::size_t operator()(T const& obj) const noexcept {
return std::hash<typename T::index_t>{}(obj.index);
}
};
}
49 changes: 43 additions & 6 deletions src/openvic-simulation/types/OrderedContainers.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#pragma once

#include <cctype>
#include <cstddef>
#include <functional>
#include <type_traits>

#include <tsl/ordered_map.h>
#include <tsl/ordered_set.h>
Expand All @@ -14,6 +16,18 @@
#include <foonathan/memory/default_allocator.hpp>
#include <foonathan/memory/std_allocator.hpp>

namespace std {
template<typename T>
struct equal_to<std::reference_wrapper<const T>> {
[[nodiscard]] bool operator()(
std::reference_wrapper<const T> const& lhs,
std::reference_wrapper<const T> const& rhs
) const noexcept {
return lhs.get() == rhs.get();
}
};
}

namespace OpenVic {
struct ordered_container_string_hash {
using is_transparent = void;
Expand Down Expand Up @@ -44,46 +58,69 @@ namespace OpenVic {
struct container_hash<char const*> : ordered_container_string_hash {};
template<typename T>
struct container_hash<T*> : std::hash<T const*> {};
template<typename T>
struct container_hash<std::reference_wrapper<T>> : std::hash<const T> {};
template<typename T>
struct container_hash<std::reference_wrapper<const T>> : std::hash<const T> {};

// Default: Use transparent equality
template<typename T>
struct default_equal_to_selector {
using type = std::equal_to<>;
};

// Specialization for reference_wrapper
template<typename T>
struct default_equal_to_selector<std::reference_wrapper<T>> {
using type = std::equal_to<std::reference_wrapper<const T>>;
};
template<typename T>
struct default_equal_to_selector<std::reference_wrapper<const T>> {
using type = std::equal_to<std::reference_wrapper<const T>>;
};

template<typename T>
using default_equal_to = typename default_equal_to_selector<T>::type;

// Useful for contiguous memory
template<
class Key, class T, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>,
class Key, class T, class Hash = container_hash<Key>, class KeyEqual = default_equal_to<Key>,
class RawAllocator = foonathan::memory::default_allocator, class IndexType = std::uint_least32_t,
class Allocator = foonathan::memory::std_allocator<std::pair<Key, T>, memory::tracker<RawAllocator>>>
using vector_ordered_map =
tsl::ordered_map<Key, T, Hash, KeyEqual, Allocator, std::vector<std::pair<Key, T>, Allocator>, IndexType>;

// Useful for stable memory addresses (so long as you don't remove or insert values)
template<
class Key, class T, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>,
class Key, class T, class Hash = container_hash<Key>, class KeyEqual = default_equal_to<Key>,
class RawAllocator = foonathan::memory::default_allocator, class IndexType = std::uint_least32_t,
class Allocator = foonathan::memory::std_allocator<std::pair<Key, T>, memory::tracker<RawAllocator>>>
using deque_ordered_map =
tsl::ordered_map<Key, T, Hash, KeyEqual, Allocator, OpenVic::utility::deque<std::pair<Key, T>, Allocator>, IndexType>;

template<
class Key, class T, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>,
class Key, class T, class Hash = container_hash<Key>, class KeyEqual = default_equal_to<Key>,
class RawAllocator = foonathan::memory::default_allocator, class IndexType = std::uint_least32_t,
class Allocator = foonathan::memory::std_allocator<std::pair<Key, T>, memory::tracker<RawAllocator>>>
using ordered_map = vector_ordered_map<Key, T, Hash, KeyEqual, RawAllocator, IndexType, Allocator>;

// Useful for contiguous memory
template<
class Key, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>,
class Key, class Hash = container_hash<Key>, class KeyEqual = default_equal_to<Key>,
class RawAllocator = foonathan::memory::default_allocator, class IndexType = std::uint_least32_t,
class Allocator = foonathan::memory::std_allocator<Key, memory::tracker<RawAllocator>>>
using vector_ordered_set = tsl::ordered_set<Key, Hash, KeyEqual, Allocator, std::vector<Key, Allocator>, IndexType>;

// Useful for stable memory addresses (so long as you don't remove or insert values)
template<
class Key, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>,
class Key, class Hash = container_hash<Key>, class KeyEqual = default_equal_to<Key>,
class RawAllocator = foonathan::memory::default_allocator, class IndexType = std::uint_least32_t,
class Allocator = foonathan::memory::std_allocator<Key, memory::tracker<RawAllocator>>>
using deque_ordered_set =
tsl::ordered_set<Key, Hash, KeyEqual, Allocator, OpenVic::utility::deque<Key, Allocator>, IndexType>;

template<
class Key, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>,
class Key, class Hash = container_hash<Key>, class KeyEqual = default_equal_to<Key>,
class RawAllocator = foonathan::memory::default_allocator, class IndexType = std::uint_least32_t,
class Allocator = foonathan::memory::std_allocator<Key, memory::tracker<RawAllocator>>>
using ordered_set = vector_ordered_set<Key, Hash, KeyEqual, RawAllocator, IndexType, Allocator>;
Expand Down