From 5fa456c21ad950a6f269b83f5e88ce8c90ae9a14 Mon Sep 17 00:00:00 2001 From: Spartan322 Date: Tue, 19 Dec 2023 18:45:09 -0500 Subject: Add diplomatic actions skeleton Add AnyRef for cheap "move only" reference Add FunctionRef for cheap "move only" function reference Based on https://github.com/think-cell/think-cell-library/blob/main/tc/base/ref.h --- src/openvic-simulation/GameManager.hpp | 2 + src/openvic-simulation/dataloader/Dataloader.cpp | 4 + .../diplomacy/DiplomacyManager.hpp | 9 ++ .../diplomacy/DiplomaticAction.cpp | 146 +++++++++++++++++++++ .../diplomacy/DiplomaticAction.hpp | 134 +++++++++++++++++++ src/openvic-simulation/types/AnyRef.hpp | 61 +++++++++ src/openvic-simulation/types/FunctionRef.hpp | 117 +++++++++++++++++ 7 files changed, 473 insertions(+) create mode 100644 src/openvic-simulation/diplomacy/DiplomacyManager.hpp create mode 100644 src/openvic-simulation/diplomacy/DiplomaticAction.cpp create mode 100644 src/openvic-simulation/diplomacy/DiplomaticAction.hpp create mode 100644 src/openvic-simulation/types/AnyRef.hpp create mode 100644 src/openvic-simulation/types/FunctionRef.hpp (limited to 'src') diff --git a/src/openvic-simulation/GameManager.hpp b/src/openvic-simulation/GameManager.hpp index 33be9d3..571b4bc 100644 --- a/src/openvic-simulation/GameManager.hpp +++ b/src/openvic-simulation/GameManager.hpp @@ -2,6 +2,7 @@ #include "openvic-simulation/misc/Decision.hpp" #include "openvic-simulation/country/Country.hpp" +#include "openvic-simulation/diplomacy/DiplomacyManager.hpp" #include "openvic-simulation/economy/EconomyManager.hpp" #include "openvic-simulation/history/HistoryManager.hpp" #include "openvic-simulation/interface/UI.hpp" @@ -36,6 +37,7 @@ namespace OpenVic { EventManager PROPERTY_REF(event_manager); DecisionManager PROPERTY_REF(decision_manager); UIManager PROPERTY_REF(ui_manager); + DiplomacyManager PROPERTY_REF(diplomacy_manager); SimulationClock PROPERTY_REF(simulation_clock); time_t session_start; /* SS-54, as well as allowing time-tracking */ diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp index f78499c..8a5f27e 100644 --- a/src/openvic-simulation/dataloader/Dataloader.cpp +++ b/src/openvic-simulation/dataloader/Dataloader.cpp @@ -915,6 +915,10 @@ bool Dataloader::load_defines(GameManager& game_manager) const { Logger::error("Failed to load on actions!"); ret = false; } + if (!game_manager.get_diplomacy_manager().get_diplomatic_action_manager().setup_diplomatic_actions()) { + Logger::error("Failed to load diplomatic actions!"); + ret = false; + } return ret; } diff --git a/src/openvic-simulation/diplomacy/DiplomacyManager.hpp b/src/openvic-simulation/diplomacy/DiplomacyManager.hpp new file mode 100644 index 0000000..c71bdbf --- /dev/null +++ b/src/openvic-simulation/diplomacy/DiplomacyManager.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "openvic-simulation/diplomacy/DiplomaticAction.hpp" + +namespace OpenVic { + class DiplomacyManager { + DiplomaticActionManager PROPERTY_REF(diplomatic_action_manager); + }; +} diff --git a/src/openvic-simulation/diplomacy/DiplomaticAction.cpp b/src/openvic-simulation/diplomacy/DiplomaticAction.cpp new file mode 100644 index 0000000..c1aa3df --- /dev/null +++ b/src/openvic-simulation/diplomacy/DiplomaticAction.cpp @@ -0,0 +1,146 @@ +#include "DiplomaticAction.hpp" + +#include +#include + +#include "openvic-simulation/types/IdentifierRegistry.hpp" +#include "openvic-simulation/utility/Logger.hpp" + +using namespace OpenVic; + +DiplomaticActionType::DiplomaticActionType(DiplomaticActionType::Initializer&& initializer) + : commit_action_caller { std::move(initializer.commit) }, + allowed_to_commit { std::move(initializer.allowed) }, get_acceptance { std::move(initializer.get_acceptance) } {} + +CancelableDiplomaticActionType::CancelableDiplomaticActionType(CancelableDiplomaticActionType::Initializer&& initializer) + : allowed_to_cancel{std::move(initializer.allowed_cancel)}, DiplomaticActionType(std::move(initializer)) {} + + +DiplomaticActionManager::DiplomaticActionManager() {} + +bool DiplomaticActionManager::add_diplomatic_action( + std::string_view identifier, DiplomaticActionType::Initializer&& initializer +) { + if (identifier.empty()) { + Logger::error("Invalid diplomatic action identifier - empty!"); + return false; + } + return diplomatic_action_types.add_item({ identifier, DiplomaticActionType { std::move(initializer) } }); +} + +bool DiplomaticActionManager::add_cancelable_diplomatic_action( + std::string_view identifier, CancelableDiplomaticActionType::Initializer&& initializer +) { + if (identifier.empty()) { + Logger::error("Invalid cancelable diplomatic action identifier - empty!"); + return false; + } + return diplomatic_action_types.add_item({ identifier, CancelableDiplomaticActionType { std::move(initializer) } }); +} + +DiplomaticActionTickCache DiplomaticActionManager::create_diplomatic_action_tick( + std::string_view identifier, Country& sender, Country& reciever, std::any context_data +) { + auto type = diplomatic_action_types.get_item_by_identifier(identifier); + + DiplomaticActionTickCache result { { sender, reciever, context_data }, type }; + type->visit([&](auto type) { + if ((result.allowed_to_commit = type.allowed_to_commit(result.argument))) { + result.acceptance = type.get_acceptance(result.argument); + } + }); + + return result; +} + +bool DiplomaticActionManager::setup_diplomatic_actions() { + using Argument = DiplomaticActionType::Argument; + + bool result = true; + + result &= add_diplomatic_action( + "form_alliance", + { [](Argument& arg) {} } + ); + result &= add_diplomatic_action( + "call_ally", + { + .commit = [](Argument& arg) {}, + .allowed = [](const Argument& arg) { return false; }, + .get_acceptance = [](const Argument& arg) { return 1; } + } + ); + result &= add_cancelable_diplomatic_action( + "request_military_access", + { + .commit = [](Argument& arg) {}, + .allowed_cancel = [](const Argument& arg) { return true; } + } + ); + result &= add_diplomatic_action( + "give_military_access", + { [](Argument& arg) {} } + ); + result &= add_diplomatic_action( + "increase_relations", + { + .commit = [](Argument& arg) {}, + .allowed = [](const Argument& arg) { return false; }, + } + ); + result &= add_diplomatic_action( + "decrease_relations", + { [](Argument& arg) {} } + ); + result &= add_diplomatic_action( + "war_subsidies", + { [](Argument& arg) {} } + ); + result &= add_diplomatic_action( + "declare_war", + { [](Argument& arg) {} } + ); + result &= add_diplomatic_action( + "offer_peace", + { [](Argument& arg) {} } + ); + result &= add_diplomatic_action( + "command_units", + { [](Argument& arg) {} } + ); + result &= add_diplomatic_action( + "discredit", + { [](Argument& arg) {} } + ); + result &= add_diplomatic_action( + "expel_advisors", + { [](Argument& arg) {} } + ); + result &= add_diplomatic_action( + "increase_opinion", + { [](Argument& arg) {} } + ); + result &= add_diplomatic_action( + "decrease_opinion", + { [](Argument& arg) {} } + ); + result &= add_diplomatic_action( + "add_to_sphere", + { [](Argument& arg) {} } + ); + result &= add_diplomatic_action( + "remove_from_sphere", + { [](Argument& arg) {} } + ); + result &= add_diplomatic_action( + "justify_war", + { [](Argument& arg) {} } + ); + result &= add_diplomatic_action( + "give_vision", + { [](Argument& arg) {} } + ); + diplomatic_action_types.lock(); + + return result; +} diff --git a/src/openvic-simulation/diplomacy/DiplomaticAction.hpp b/src/openvic-simulation/diplomacy/DiplomaticAction.hpp new file mode 100644 index 0000000..7254510 --- /dev/null +++ b/src/openvic-simulation/diplomacy/DiplomaticAction.hpp @@ -0,0 +1,134 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "openvic-simulation/country/Country.hpp" +#include "openvic-simulation/types/FunctionRef.hpp" +#include "openvic-simulation/types/IdentifierRegistry.hpp" + +namespace OpenVic { + struct DiplomaticActionType { + friend struct DiplomaticActionManager; + friend struct CancelableDiplomaticActionType; + + struct Argument { + Country& sender; + Country& reciever; + std::any context_data; + }; + + using allowed_to_commit_func = FunctionRef; + using get_acceptance_func = FunctionRef; + using commit_action_func = FunctionRef; + + static bool allowed_to_commit_default(const Argument& argument) { + return true; + } + + static std::int32_t get_acceptance_default(const Argument& argument) { + return 1; + } + + struct Initializer { + commit_action_func commit; + allowed_to_commit_func allowed = allowed_to_commit_default; + get_acceptance_func get_acceptance = get_acceptance_default; + }; + + const commit_action_func commit_action_caller; + const allowed_to_commit_func allowed_to_commit = allowed_to_commit_default; + const get_acceptance_func get_acceptance = get_acceptance_default; + + void commit_action(Argument& arg) const { + commit_action_caller(arg); + } + + private: + DiplomaticActionType(Initializer&& initializer); + }; + + struct CancelableDiplomaticActionType : DiplomaticActionType { + friend struct DiplomaticActionManager; + + using allowed_to_cancel_func = FunctionRef; + + + static bool allowed_to_cancel_default(const Argument& argument) { + return true; + } + + struct Initializer { + commit_action_func commit; + allowed_to_commit_func allowed = allowed_to_commit_default; + get_acceptance_func get_acceptance = get_acceptance_default; + allowed_to_cancel_func allowed_cancel = allowed_to_cancel_default; + + operator DiplomaticActionType::Initializer() { + return {commit, allowed, get_acceptance}; + } + }; + + const allowed_to_cancel_func allowed_to_cancel = allowed_to_cancel_default; + + private: + CancelableDiplomaticActionType(Initializer&& initializer); + }; + + struct DiplomaticActionTickCache; + + struct DiplomaticActionTypeStorage : std::variant, HasIdentifier { + using base_type = std::variant; + + template + constexpr DiplomaticActionTypeStorage(std::string_view identifier, T&& t) : HasIdentifier(identifier), base_type(t) {} + + template + constexpr decltype(auto) visit(Visitor&& vis){ + return std::visit(std::forward(vis), *this); + } + + template + constexpr decltype(auto) visit(Visitor&& vis) const { + return std::visit(std::forward(vis), *this); + } + + constexpr bool is_cancelable() const { + return visit([](auto&& arg) -> bool { + using T = std::decay_t; + if constexpr(std::same_as) { + return true; + } else { + return false; + } + }); + } + }; + + struct DiplomaticActionTickCache { + DiplomaticActionType::Argument argument; + const DiplomaticActionTypeStorage* type; + bool allowed_to_commit; + std::int32_t acceptance = -1; + }; + + struct DiplomaticActionManager { + private: + IdentifierRegistry IDENTIFIER_REGISTRY(diplomatic_action_type); + + public: + DiplomaticActionManager(); + + bool add_diplomatic_action(std::string_view identifier, DiplomaticActionType::Initializer&& initializer); + bool add_cancelable_diplomatic_action(std::string_view identifier, CancelableDiplomaticActionType::Initializer&& initializer); + + DiplomaticActionTickCache + create_diplomatic_action_tick(std::string_view identifier, Country& sender, Country& reciever, std::any context_data); + + bool setup_diplomatic_actions(); + }; +} diff --git a/src/openvic-simulation/types/AnyRef.hpp b/src/openvic-simulation/types/AnyRef.hpp new file mode 100644 index 0000000..b50a039 --- /dev/null +++ b/src/openvic-simulation/types/AnyRef.hpp @@ -0,0 +1,61 @@ +#pragma once + +#include + +namespace OpenVic { + // Based on https://github.com/think-cell/think-cell-library/blob/b9c84dd7fc926fad80829ed49705fa51afe36e87/tc/base/ref.h + // Boost Software License - Version 1.0 - August 17th, 2003 + + // Permission is hereby granted, free of charge, to any person or organization + // obtaining a copy of the software and accompanying documentation covered by + // this license (the "Software") to use, reproduce, display, distribute, + // execute, and transmit the Software, and to prepare derivative works of the + // Software, and to permit third-parties to whom the Software is furnished to + // do so, all subject to the following: + + // The copyright notices in the Software and this entire statement, including + // the above license grant, this restriction and the following disclaimer, + // must be included in all copies of the Software, in whole or in part, and + // all derivative works of the Software, unless such copies or derivative + // works are solely in the form of machine-executable object code generated by + // a source language processor. + + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + // DEALINGS IN THE SOFTWARE. + union AnyRef { + // Any pointer to function can be converted to a pointer to a different function type. Calling the + // function through a pointer to a different function type is undefined, but converting such pointer + // back to pointer to the original function type yields the pointer to the original function. + // https://en.cppreference.com/w/cpp/language/reinterpret_cast + + template + [[nodiscard]] static constexpr T* as_mutable_ptr(T const* pt) noexcept { + return const_cast(pt); + } + + template + explicit AnyRef(RefT& ref) noexcept : m_pvRef(std::addressof(ref)) {} + + template + requires std::is_function::value + explicit AnyRef(RefT& ref) noexcept : m_fpvRef(reinterpret_cast(std::addressof(ref))) {} + + template // may be const and/or volatile + RefT& get_ref() const& noexcept { + static_assert(!std::is_reference::value); + if constexpr (std::is_function::value) { + return *reinterpret_cast(m_fpvRef); + } else { + return *static_cast(as_mutable_ptr(m_pvRef)); + } + } + + void const* m_pvRef; + void (*m_fpvRef)(); + }; +} diff --git a/src/openvic-simulation/types/FunctionRef.hpp b/src/openvic-simulation/types/FunctionRef.hpp new file mode 100644 index 0000000..1ca5bb7 --- /dev/null +++ b/src/openvic-simulation/types/FunctionRef.hpp @@ -0,0 +1,117 @@ +#pragma once + +#include +#include +#include + +#include "openvic-simulation/types/AnyRef.hpp" + +namespace OpenVic { + // Based on https://github.com/think-cell/think-cell-library/blob/b9c84dd7fc926fad80829ed49705fa51afe36e87/tc/base/ref.h + // Boost Software License - Version 1.0 - August 17th, 2003 + + // Permission is hereby granted, free of charge, to any person or organization + // obtaining a copy of the software and accompanying documentation covered by + // this license (the "Software") to use, reproduce, display, distribute, + // execute, and transmit the Software, and to prepare derivative works of the + // Software, and to permit third-parties to whom the Software is furnished to + // do so, all subject to the following: + + // The copyright notices in the Software and this entire statement, including + // the above license grant, this restriction and the following disclaimer, + // must be included in all copies of the Software, in whole or in part, and + // all derivative works of the Software, unless such copies or derivative + // works are solely in the form of machine-executable object code generated by + // a source language processor. + + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + // DEALINGS IN THE SOFTWARE. + template + struct FunctionRefBase { + template + using type_erased_function_ptr = Ret2 (*)(AnyRef, Args2...) noexcept(bNoExcept2); + + template + struct make_type_erased_function_ptr final { + type_erased_function_ptr operator()() const& noexcept { + return [](AnyRef anyref, + Args2... args) noexcept(bNoExcept2) -> Ret2 { // implicit cast of stateless lambda to function pointer + return std::invoke( + anyref.template get_ref(), std::forward(args)... + ); // MAYTHROW unless bNoExcept + }; + } + }; + + template + struct make_type_erased_function_ptr final { + type_erased_function_ptr operator()() const& noexcept { + return [](AnyRef anyref, + Args2... args) noexcept(bNoExcept2) { // implicit cast of stateless lambda to function pointer + std::invoke(anyref.template get_ref(), std::forward(args)...); // MAYTHROW unless bNoExcept + }; + } + }; + + template + [[nodiscard]] static constexpr T& as_lvalue(T&& t) noexcept { + return t; + } + + FunctionRefBase(FunctionRefBase const&) noexcept = default; + + Ret operator()(Args... args) const& noexcept(bNoExcept) { + return m_pfuncTypeErased(m_anyref, std::forward(args)...); // MAYTHROW unless bNoExcept + } + + + template + struct decayed_derived_from : std::bool_constant::type, Base>> { + static_assert(std::same_as, Base>); + }; + + template + requires(!decayed_derived_from::value) && + std::invocable&, Args...> && + (std::convertible_to< + decltype(std::invoke(std::declval&>(), std::declval()...)), Ret> || + std::is_void::value) + FunctionRefBase(Func&& func) noexcept + : m_pfuncTypeErased(make_type_erased_function_ptr, Ret, Args...> {}()), + m_anyref(as_lvalue(func)) { + static_assert( + !std::is_member_function_pointer::value, + "Raw member functions are not supported (how would you call them?). Pass in a lambda or use " + "std::mem_fn instead." + ); + static_assert(!std::is_pointer::value, "Pass in functions rather than function pointers."); + // Checking the noexcept value of the function call is commented out because MAYTHROW is widely used in generic code + // such as for_each, range_adaptor... static_assert(!bNoExcept || + // noexcept(std::declval&>()(std::declval()...))); + } + + private: + type_erased_function_ptr m_pfuncTypeErased; + AnyRef m_anyref; + }; + + template + struct FunctionRef; + + template + struct FunctionRef : FunctionRefBase { + using base_ = typename FunctionRef::FunctionRefBase; + using base_::base_; + }; + + template + struct FunctionRef : FunctionRefBase { + using base_ = typename FunctionRef::FunctionRefBase; + using base_::base_; + }; +} -- cgit v1.2.3-56-ga3b1