aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvic-simulation')
-rw-r--r--src/openvic-simulation/GameManager.hpp2
-rw-r--r--src/openvic-simulation/dataloader/Dataloader.cpp4
-rw-r--r--src/openvic-simulation/diplomacy/DiplomacyManager.hpp9
-rw-r--r--src/openvic-simulation/diplomacy/DiplomaticAction.cpp146
-rw-r--r--src/openvic-simulation/diplomacy/DiplomaticAction.hpp134
-rw-r--r--src/openvic-simulation/types/AnyRef.hpp61
-rw-r--r--src/openvic-simulation/types/FunctionRef.hpp117
7 files changed, 473 insertions, 0 deletions
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 <string_view>
+#include <variant>
+
+#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 <any>
+#include <concepts>
+#include <cstdint>
+#include <string_view>
+#include <type_traits>
+#include <variant>
+
+#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<bool(const Argument&)>;
+ using get_acceptance_func = FunctionRef<std::int32_t(const Argument&)>;
+ using commit_action_func = FunctionRef<void(Argument&)>;
+
+ 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<bool(const Argument&)>;
+
+
+ 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<DiplomaticActionType, CancelableDiplomaticActionType>, HasIdentifier {
+ using base_type = std::variant<DiplomaticActionType, CancelableDiplomaticActionType>;
+
+ template<typename T>
+ constexpr DiplomaticActionTypeStorage(std::string_view identifier, T&& t) : HasIdentifier(identifier), base_type(t) {}
+
+ template<class Visitor>
+ constexpr decltype(auto) visit(Visitor&& vis){
+ return std::visit(std::forward<Visitor>(vis), *this);
+ }
+
+ template<class Visitor>
+ constexpr decltype(auto) visit(Visitor&& vis) const {
+ return std::visit(std::forward<Visitor>(vis), *this);
+ }
+
+ constexpr bool is_cancelable() const {
+ return visit([](auto&& arg) -> bool {
+ using T = std::decay_t<decltype(arg)>;
+ if constexpr(std::same_as<T, CancelableDiplomaticActionType>) {
+ 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<DiplomaticActionTypeStorage> 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 <memory>
+
+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<typename T>
+ [[nodiscard]] static constexpr T* as_mutable_ptr(T const* pt) noexcept {
+ return const_cast<T*>(pt);
+ }
+
+ template<typename RefT>
+ explicit AnyRef(RefT& ref) noexcept : m_pvRef(std::addressof(ref)) {}
+
+ template<typename RefT>
+ requires std::is_function<RefT>::value
+ explicit AnyRef(RefT& ref) noexcept : m_fpvRef(reinterpret_cast<void (*)()>(std::addressof(ref))) {}
+
+ template<typename RefT> // may be const and/or volatile
+ RefT& get_ref() const& noexcept {
+ static_assert(!std::is_reference<RefT>::value);
+ if constexpr (std::is_function<RefT>::value) {
+ return *reinterpret_cast<RefT*>(m_fpvRef);
+ } else {
+ return *static_cast<RefT*>(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 <functional>
+#include <type_traits>
+#include <utility>
+
+#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<bool bNoExcept, typename Ret, typename... Args>
+ struct FunctionRefBase {
+ template<bool bNoExcept2, typename Ret2, typename... Args2>
+ using type_erased_function_ptr = Ret2 (*)(AnyRef, Args2...) noexcept(bNoExcept2);
+
+ template<bool bNoExcept2, typename Func, typename Ret2, typename... Args2>
+ struct make_type_erased_function_ptr final {
+ type_erased_function_ptr<bNoExcept2, Ret2, Args2...> 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<Func>(), std::forward<Args2>(args)...
+ ); // MAYTHROW unless bNoExcept
+ };
+ }
+ };
+
+ template<bool bNoExcept2, typename Func, typename... Args2>
+ struct make_type_erased_function_ptr<bNoExcept2, Func, void, Args2...> final {
+ type_erased_function_ptr<bNoExcept2, void, Args2...> operator()() const& noexcept {
+ return [](AnyRef anyref,
+ Args2... args) noexcept(bNoExcept2) { // implicit cast of stateless lambda to function pointer
+ std::invoke(anyref.template get_ref<Func>(), std::forward<Args2>(args)...); // MAYTHROW unless bNoExcept
+ };
+ }
+ };
+
+ template<typename T>
+ [[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>(args)...); // MAYTHROW unless bNoExcept
+ }
+
+
+ template<typename Derived, typename Base>
+ struct decayed_derived_from : std::bool_constant<std::derived_from<typename std::decay<Derived>::type, Base>> {
+ static_assert(std::same_as<std::decay_t<Base>, Base>);
+ };
+
+ template<typename Func>
+ requires(!decayed_derived_from<Func, FunctionRefBase>::value) &&
+ std::invocable<std::remove_reference_t<Func>&, Args...> &&
+ (std::convertible_to<
+ decltype(std::invoke(std::declval<std::remove_reference_t<Func>&>(), std::declval<Args>()...)), Ret> ||
+ std::is_void<Ret>::value)
+ FunctionRefBase(Func&& func) noexcept
+ : m_pfuncTypeErased(make_type_erased_function_ptr<bNoExcept, std::remove_reference_t<Func>, Ret, Args...> {}()),
+ m_anyref(as_lvalue(func)) {
+ static_assert(
+ !std::is_member_function_pointer<Func>::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<Func>::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<tc::decay_t<Func>&>()(std::declval<Args>()...)));
+ }
+
+ private:
+ type_erased_function_ptr<bNoExcept, Ret, Args...> m_pfuncTypeErased;
+ AnyRef m_anyref;
+ };
+
+ template<typename Sig>
+ struct FunctionRef;
+
+ template<typename Ret, typename... Args>
+ struct FunctionRef<Ret(Args...)> : FunctionRefBase</*bNoExcept*/ false, Ret, Args...> {
+ using base_ = typename FunctionRef::FunctionRefBase;
+ using base_::base_;
+ };
+
+ template<typename Ret, typename... Args>
+ struct FunctionRef<Ret(Args...) noexcept> : FunctionRefBase</*bNoExcept*/ true, Ret, Args...> {
+ using base_ = typename FunctionRef::FunctionRefBase;
+ using base_::base_;
+ };
+}