From 48558fdfec509942515b0e2d92e3f1357b201400 Mon Sep 17 00:00:00 2001 From: markomitos Date: Wed, 1 Mar 2023 23:20:58 +0100 Subject: Add Date to extension For absolute simulation dates Add TimeSpan to extension For relative simulation time Add Simulation Speed Management to extension Add Visual Studio directory to .gitignore Co-authored-by: ClarkeCode Co-authored-by: Hop311 --- .gitignore | 3 ++ extension/src/Simulation.cpp | 64 ++++++++++++++++++++++++ extension/src/Simulation.hpp | 30 +++++++++-- extension/src/openvic2/Date.cpp | 108 ++++++++++++++++++++++++++++++++++++++++ extension/src/openvic2/Date.hpp | 83 ++++++++++++++++++++++++++++++ 5 files changed, 283 insertions(+), 5 deletions(-) create mode 100644 extension/src/Simulation.cpp create mode 100644 extension/src/openvic2/Date.cpp create mode 100644 extension/src/openvic2/Date.hpp diff --git a/.gitignore b/.gitignore index 125f143..596bc88 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,9 @@ !.vscode/launch.json !.vscode/tasks.json +# Visual Studio +.vs/ + # Godot 4+ specific ignores .godot/ game/bin/openvic2/* diff --git a/extension/src/Simulation.cpp b/extension/src/Simulation.cpp new file mode 100644 index 0000000..5ea99c5 --- /dev/null +++ b/extension/src/Simulation.cpp @@ -0,0 +1,64 @@ +#include "Simulation.hpp" + +namespace OpenVic2 { + void Simulation::togglePauseState() { + this->isPaused = !isPaused; + } + + bool Simulation::getPauseState() { + return this->isPaused; + } + + void Simulation::increaseSimulationSpeed() { + switch (this->currentSpeed) { + case(Speed::Speed1): + this->currentSpeed = Speed::Speed2; + break; + case(Speed::Speed2): + this->currentSpeed = Speed::Speed3; + break; + case(Speed::Speed3): + this->currentSpeed = Speed::Speed4; + break; + case(Speed::Speed4): + this->currentSpeed = Speed::Speed5; + break; + } + } + + void Simulation::decreaseSimulationSpeed() { + switch (this->currentSpeed) { + case(Speed::Speed2): + this->currentSpeed = Speed::Speed1; + break; + case(Speed::Speed3): + this->currentSpeed = Speed::Speed2; + break; + case(Speed::Speed4): + this->currentSpeed = Speed::Speed3; + break; + case(Speed::Speed5): + this->currentSpeed = Speed::Speed4; + break; + } + } + + void Simulation::setSimulationSpeed(Speed speed) { + this->currentSpeed = speed; + } + + int Simulation::getSimulationSpeed() { + return static_cast(this->currentSpeed); + } + + void Simulation::conditionallyAdvanceSimulation() { + if (!(this->isPaused)) { + std::chrono::time_point previousTime = this->lastPolledTime; + std::chrono::time_point currentTime = std::chrono::high_resolution_clock::now(); + if (std::chrono::duration_cast(currentTime - previousTime).count() >= this->getSimulationSpeed()) { + this->lastPolledTime = currentTime; + this->inGameDate++; + } + } + } +} diff --git a/extension/src/Simulation.hpp b/extension/src/Simulation.hpp index b84016b..58ba7c7 100644 --- a/extension/src/Simulation.hpp +++ b/extension/src/Simulation.hpp @@ -2,28 +2,39 @@ #include #include +#include +#include "openvic2/Date.hpp" namespace OpenVic2 { class Simulation : public godot::Object { GDCLASS(Simulation, godot::Object) std::vector exampleProvinces; + enum class Speed { Speed1 = 4000, Speed2 = 3000, Speed3 = 2000, Speed4 = 1000, Speed5 = 100, Speed6 = 1 }; + + std::chrono::time_point lastPolledTime; + bool isPaused; + Speed currentSpeed; + Date inGameDate; + //BEGIN BOILERPLATE inline static Simulation* _simulation = nullptr; - protected: + protected: static void _bind_methods() { godot::ClassDB::bind_method(godot::D_METHOD("conductSimulationStep"), &Simulation::conductSimulationStep); godot::ClassDB::bind_method(godot::D_METHOD("queryProvinceSize"), &Simulation::queryProvinceSize); } - public: + public: inline static Simulation* get_singleton() { return _simulation; } - inline Simulation() { + inline Simulation() : inGameDate(1836, 1, 1) { ERR_FAIL_COND(_simulation != nullptr); _simulation = this; - + this->lastPolledTime = std::chrono::high_resolution_clock::now(); + this->isPaused = false; + this->currentSpeed = Speed::Speed1; exampleProvinces.resize(10, 1); } inline ~Simulation() { @@ -32,6 +43,13 @@ namespace OpenVic2 { } //END BOILERPLATE + void togglePauseState(); + bool getPauseState(); + void increaseSimulationSpeed(); + void decreaseSimulationSpeed(); + void setSimulationSpeed(Speed speed); + int getSimulationSpeed(); + inline void conductSimulationStep() { for (uint64_t x = 0; x < exampleProvinces.size(); x++) { exampleProvinces[x] += (x + 1); @@ -44,5 +62,7 @@ namespace OpenVic2 { } return exampleProvinces[provinceID]; } + + void conditionallyAdvanceSimulation(); }; -} +} \ No newline at end of file diff --git a/extension/src/openvic2/Date.cpp b/extension/src/openvic2/Date.cpp new file mode 100644 index 0000000..3c5b8d8 --- /dev/null +++ b/extension/src/openvic2/Date.cpp @@ -0,0 +1,108 @@ +#include +#include "Date.hpp" + +namespace OpenVic2 { + bool Timespan::operator< (Timespan const& other) const { return days < other.days; } + bool Timespan::operator> (Timespan const& other) const { return days > other.days; } + bool Timespan::operator<= (Timespan const& other) const { return days <= other.days; } + bool Timespan::operator>= (Timespan const& other) const { return days >= other.days; } + bool Timespan::operator== (Timespan const& other) const { return days == other.days; } + bool Timespan::operator!= (Timespan const& other) const { return days != other.days; } + + Timespan Timespan::operator+ (Timespan const& other) const { return Timespan(days + other.days); } + Timespan Timespan::operator- (Timespan const& other) const { return Timespan(days - other.days); } + Timespan Timespan::operator* (int64_t const& factor) const { return Timespan(days * factor); } + Timespan Timespan::operator/ (int64_t const& factor) const { return Timespan(days / factor); } + + Timespan& Timespan::operator+= (Timespan const& other) { + days += other.days; + return *this; + } + Timespan& Timespan::operator-= (Timespan const& other) { + days -= other.days; + return *this; + } + + Timespan fromYearZero(year_t year, month_t month, date_t day) { + int64_t daysElapsed = year * DAYS_IN_YEAR; + size_t daysSinceMonthStart = (day == 0) ? 0 : day - 1; //Underflow protection + for (size_t x = 0; x < month && x < MONTHS_IN_YEAR; x++) { + daysElapsed += DAYS_IN_MONTH[x]; + } + daysElapsed += daysSinceMonthStart; + return Timespan(daysElapsed); + } + + //This function is not set up to handle dates before Year 0 + YearMonthDayBundle toGregorianDate(Timespan const& timespan) { + year_t year = 0; + month_t month = 0; + date_t day = 0; + + if (timespan >= 0) { + year = timespan.days / DAYS_IN_YEAR; + int64_t remainingDays = timespan.days % DAYS_IN_YEAR; + + for (size_t x = 0; x < MONTHS_IN_YEAR && remainingDays >= DAYS_IN_MONTH[x]; x++) { + remainingDays -= DAYS_IN_MONTH[x]; + month++; + } + + //Corrects month and day to be 1-indexed + month++; + day++; + } + return std::make_tuple(year, month, day); + } + + + Date::Date(Timespan const& timespan) : ts(timespan) { updateDate(ts); } + + Date::Date(year_t year, month_t month, date_t day) { + ts = fromYearZero(year, month, day); + updateDate(ts); + } + + void Date::updateDate(Timespan const& timespan) { + gregorianDate = toGregorianDate(timespan); + } + + size_t Date::getDay() const { return std::get<2>(gregorianDate); } + size_t Date::getMonth() const { return std::get<1>(gregorianDate); } + size_t Date::getYear() const { return std::get<0>(gregorianDate); } + + bool Date::operator< (Date const& other) const { return ts < other.ts; } + bool Date::operator> (Date const& other) const { return ts > other.ts; } + bool Date::operator<= (Date const& other) const { return ts <= other.ts; } + bool Date::operator>= (Date const& other) const { return ts >= other.ts; } + bool Date::operator== (Date const& other) const { return ts == other.ts; } + bool Date::operator!= (Date const& other) const { return ts != other.ts; } + + Date Date::operator+ (Timespan timespan) const { return Date(ts + timespan); } + Timespan Date::operator- (Date const& other) const { return ts - other.ts; } + + Date& Date::operator+= (Timespan const& timespan) { + ts += timespan; + updateDate(ts); + return *this; + } + Date& Date::operator-= (Timespan const& timespan) { + ts -= timespan; + updateDate(ts); + return *this; + } + Date Date::operator++ (int) { + Date oldCopy = *this; + (*this) += 1; + return oldCopy; + } + + Date::operator std::string() const { + std::stringstream ss; + ss << getYear() << '.' << getMonth() << '.' << getDay(); + return ss.str(); + } + std::ostream &operator<<(std::ostream &out, Date const& date) { + return out << static_cast(date); + } +} diff --git a/extension/src/openvic2/Date.hpp b/extension/src/openvic2/Date.hpp new file mode 100644 index 0000000..841b118 --- /dev/null +++ b/extension/src/openvic2/Date.hpp @@ -0,0 +1,83 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace OpenVic2 { + //A relative period between points in time, measured in days + struct Timespan { + int64_t days; + + Timespan() : days(0) {} + Timespan(int64_t const& value) : days(value) {} + + bool operator< (Timespan const& other) const; + bool operator> (Timespan const& other) const; + bool operator<= (Timespan const& other) const; + bool operator>= (Timespan const& other) const; + bool operator== (Timespan const& other) const; + bool operator!= (Timespan const& other) const; + + Timespan operator+ (Timespan const& other) const; + Timespan operator- (Timespan const& other) const; + Timespan operator* (int64_t const& factor) const; + Timespan operator/ (int64_t const& factor) const; + + Timespan& operator+= (Timespan const& other); + Timespan& operator-= (Timespan const& other); + }; + + static constexpr size_t MONTHS_IN_YEAR = 12; + static constexpr size_t DAYS_IN_YEAR = 365; + static constexpr size_t DAYS_IN_MONTH[MONTHS_IN_YEAR] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + + using date_t = uint8_t; + using month_t = uint8_t; + using year_t = uint16_t; + using YearMonthDayBundle = std::tuple; + + //Represents an in-game date + //Note: Current implementation does not account for leap-years, or dates before Year 0 + struct Date { + private: + YearMonthDayBundle gregorianDate; + //Number of days since Jan 1st, Year 0 + Timespan ts; + + public: + //The Timespan is considered to be the number of days since Jan 1st, Year 0 + Date(Timespan const& timespan); + + //Year month day specification + Date(year_t year = 1836, month_t month = 1, date_t day = 1); + + private: + void updateDate(Timespan const& timespan); + + public: + size_t getDay() const; + size_t getMonth() const; + size_t getYear() const; + + bool operator< (Date const& other) const; + bool operator> (Date const& other) const; + bool operator<= (Date const& other) const; + bool operator>= (Date const& other) const; + bool operator== (Date const& other) const; + bool operator!= (Date const& other) const; + + Date operator+ (Timespan timespan) const; + Timespan operator- (Date const& other) const; + + Date& operator+= (Timespan const& timespan); + Date& operator-= (Timespan const& timespan); + //Postfix increment + Date operator++ (int); + + explicit operator std::string() const; + friend std::ostream& operator<< (std::ostream& out, Date const& date); + }; +} -- cgit v1.2.3-56-ga3b1