diff --git a/src/openvic-simulation/GameManager.cpp b/src/openvic-simulation/GameManager.cpp index 369e269e..a4d0594b 100644 --- a/src/openvic-simulation/GameManager.cpp +++ b/src/openvic-simulation/GameManager.cpp @@ -1,6 +1,7 @@ #include "GameManager.hpp" #include +#include #include #include @@ -76,7 +77,7 @@ bool GameManager::load_mods(memory::vector const& mods_to_find) bool ret = true; - vector_ordered_set load_list; + vector_ordered_set> 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. @@ -94,8 +95,8 @@ bool GameManager::load_mods(memory::vector const& mods_to_find) continue; } - Mod const* mod_ptr = &*it; - vector_ordered_set dependencies = mod_ptr->generate_dependency_list(&ret); + Mod const& mod = *it; + vector_ordered_set> dependencies = mod.generate_dependency_list(&ret); if(!ret) { continue; } @@ -104,15 +105,15 @@ bool GameManager::load_mods(memory::vector 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); } } @@ -122,9 +123,9 @@ bool GameManager::load_mods(memory::vector const& mods_to_find) vector_ordered_set 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); } } diff --git a/src/openvic-simulation/dataloader/ModManager.cpp b/src/openvic-simulation/dataloader/ModManager.cpp index 79d013ea..8a970883 100644 --- a/src/openvic-simulation/dataloader/ModManager.cpp +++ b/src/openvic-simulation/dataloader/ModManager.cpp @@ -1,5 +1,6 @@ #include "ModManager.hpp" +#include #include #include "openvic-simulation/core/error/ErrorMacros.hpp" @@ -7,7 +8,6 @@ #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; @@ -27,34 +27,40 @@ Mod::Mod( replace_paths { new_replace_paths }, dependencies { new_dependencies } {} -vector_ordered_set Mod::generate_dependency_list(bool* success) const { +vector_ordered_set> Mod::generate_dependency_list(bool* success) const { static constexpr size_t MAX_RECURSE = 16; size_t current_recurse = 0; - vector_ordered_set result; + vector_ordered_set> result; - auto dep_cycle = [this, ¤t_recurse](auto self, Mod const* mod, vector_ordered_set& dep_list) -> bool { + auto dep_cycle = [this, ¤t_recurse]( + auto self, + Mod const& mod, + vector_ordered_set>& 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); } @@ -62,7 +68,7 @@ vector_ordered_set Mod::generate_dependency_list(bool* success) cons 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; } @@ -100,20 +106,16 @@ bool ModManager::load_mod_file(ast::NodeCPtr root) { return true; } -void ModManager::set_loaded_mods(memory::vector&& new_loaded_mods) { +void ModManager::set_loaded_mods(memory::vector>&& 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 const& ModManager::get_loaded_mods() const { - return loaded_mods; -} - size_t ModManager::get_loaded_mod_count() const { return loaded_mods.size(); } diff --git a/src/openvic-simulation/dataloader/ModManager.hpp b/src/openvic-simulation/dataloader/ModManager.hpp index 0eac7f91..20a6837b 100644 --- a/src/openvic-simulation/dataloader/ModManager.hpp +++ b/src/openvic-simulation/dataloader/ModManager.hpp @@ -1,11 +1,13 @@ #pragma once #include +#include #include #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; @@ -32,22 +34,21 @@ namespace OpenVic { ); Mod(Mod&&) = default; - vector_ordered_set generate_dependency_list(bool* success = nullptr) const; + vector_ordered_set> generate_dependency_list(bool* success = nullptr) const; }; struct ModManager { private: IdentifierRegistry IDENTIFIER_REGISTRY(mod); - memory::vector loaded_mods; + memory::vector> SPAN_PROPERTY(loaded_mods); bool mods_loaded = false; public: ModManager(); bool load_mod_file(ast::NodeCPtr root); - void set_loaded_mods(memory::vector&& new_loaded_mods); - memory::vector const& get_loaded_mods() const; + void set_loaded_mods(memory::vector>&& new_loaded_mods); size_t get_loaded_mod_count() const; }; } \ No newline at end of file diff --git a/src/openvic-simulation/types/HasIdentifier.hpp b/src/openvic-simulation/types/HasIdentifier.hpp index f7d7a803..58b87233 100644 --- a/src/openvic-simulation/types/HasIdentifier.hpp +++ b/src/openvic-simulation/types/HasIdentifier.hpp @@ -1,14 +1,14 @@ #pragma once -#include #include +#include #include #include #include -#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 { @@ -30,6 +30,12 @@ namespace OpenVic { HasIdentifier(HasIdentifier&&) = default; HasIdentifier& operator=(HasIdentifier const&) = delete; HasIdentifier& operator=(HasIdentifier&&) = delete; + + template T> + requires (!has_index) + 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) { @@ -95,4 +101,14 @@ struct fmt::formatter : fmt::formatter { fmt::format_context::iterator format(T const& has_id, fmt::format_context& ctx) const { return fmt::formatter::format(has_id.get_name(), ctx); } -}; \ No newline at end of file +}; + +namespace std { + template + requires (!OpenVic::has_index) + struct hash { + [[nodiscard]] std::size_t operator()(T const& obj) const noexcept { + return std::hash{}(obj.get_identifier()); + } + }; +} \ No newline at end of file diff --git a/src/openvic-simulation/types/HasIndex.hpp b/src/openvic-simulation/types/HasIndex.hpp index 1fcbc731..740e94a3 100644 --- a/src/openvic-simulation/types/HasIndex.hpp +++ b/src/openvic-simulation/types/HasIndex.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include #include "openvic-simulation/core/template/Concepts.hpp" @@ -26,4 +28,13 @@ namespace OpenVic { return index == rhs.index; } }; +} + +namespace std { + template + struct hash { + [[nodiscard]] std::size_t operator()(T const& obj) const noexcept { + return std::hash{}(obj.index); + } + }; } \ No newline at end of file diff --git a/src/openvic-simulation/types/OrderedContainers.hpp b/src/openvic-simulation/types/OrderedContainers.hpp index d3af3e8e..8d17635f 100644 --- a/src/openvic-simulation/types/OrderedContainers.hpp +++ b/src/openvic-simulation/types/OrderedContainers.hpp @@ -1,7 +1,9 @@ #pragma once #include +#include #include +#include #include #include @@ -14,6 +16,18 @@ #include #include +namespace std { + template + struct equal_to> { + [[nodiscard]] bool operator()( + std::reference_wrapper const& lhs, + std::reference_wrapper const& rhs + ) const noexcept { + return lhs.get() == rhs.get(); + } + }; +} + namespace OpenVic { struct ordered_container_string_hash { using is_transparent = void; @@ -44,10 +58,33 @@ namespace OpenVic { struct container_hash : ordered_container_string_hash {}; template struct container_hash : std::hash {}; + template + struct container_hash> : std::hash {}; + template + struct container_hash> : std::hash {}; + + // Default: Use transparent equality + template + struct default_equal_to_selector { + using type = std::equal_to<>; + }; + + // Specialization for reference_wrapper + template + struct default_equal_to_selector> { + using type = std::equal_to>; + }; + template + struct default_equal_to_selector> { + using type = std::equal_to>; + }; + + template + using default_equal_to = typename default_equal_to_selector::type; // Useful for contiguous memory template< - class Key, class T, class Hash = container_hash, class KeyEqual = std::equal_to<>, + class Key, class T, class Hash = container_hash, class KeyEqual = default_equal_to, class RawAllocator = foonathan::memory::default_allocator, class IndexType = std::uint_least32_t, class Allocator = foonathan::memory::std_allocator, memory::tracker>> using vector_ordered_map = @@ -55,35 +92,35 @@ namespace OpenVic { // Useful for stable memory addresses (so long as you don't remove or insert values) template< - class Key, class T, class Hash = container_hash, class KeyEqual = std::equal_to<>, + class Key, class T, class Hash = container_hash, class KeyEqual = default_equal_to, class RawAllocator = foonathan::memory::default_allocator, class IndexType = std::uint_least32_t, class Allocator = foonathan::memory::std_allocator, memory::tracker>> using deque_ordered_map = tsl::ordered_map, Allocator>, IndexType>; template< - class Key, class T, class Hash = container_hash, class KeyEqual = std::equal_to<>, + class Key, class T, class Hash = container_hash, class KeyEqual = default_equal_to, class RawAllocator = foonathan::memory::default_allocator, class IndexType = std::uint_least32_t, class Allocator = foonathan::memory::std_allocator, memory::tracker>> using ordered_map = vector_ordered_map; // Useful for contiguous memory template< - class Key, class Hash = container_hash, class KeyEqual = std::equal_to<>, + class Key, class Hash = container_hash, class KeyEqual = default_equal_to, class RawAllocator = foonathan::memory::default_allocator, class IndexType = std::uint_least32_t, class Allocator = foonathan::memory::std_allocator>> using vector_ordered_set = tsl::ordered_set, IndexType>; // Useful for stable memory addresses (so long as you don't remove or insert values) template< - class Key, class Hash = container_hash, class KeyEqual = std::equal_to<>, + class Key, class Hash = container_hash, class KeyEqual = default_equal_to, class RawAllocator = foonathan::memory::default_allocator, class IndexType = std::uint_least32_t, class Allocator = foonathan::memory::std_allocator>> using deque_ordered_set = tsl::ordered_set, IndexType>; template< - class Key, class Hash = container_hash, class KeyEqual = std::equal_to<>, + class Key, class Hash = container_hash, class KeyEqual = default_equal_to, class RawAllocator = foonathan::memory::default_allocator, class IndexType = std::uint_least32_t, class Allocator = foonathan::memory::std_allocator>> using ordered_set = vector_ordered_set;