From cfdce91eed6c0247bb02973c5798549d8405c1c0 Mon Sep 17 00:00:00 2001 From: fallahn Date: Sat, 9 Nov 2024 13:29:37 +0000 Subject: [PATCH] first pass time of day calculation --- libsocial/include/Social.hpp | 2 + samples/golf/golf.vcxproj | 2 + samples/golf/golf.vcxproj.filters | 18 +- samples/golf/src/golf/CMakeLists.txt | 1 + samples/golf/src/golf/MenuState.cpp | 35 +--- samples/golf/src/golf/TimeOfDay.cpp | 266 +++++++++++++++++++++++++++ samples/golf/src/golf/TimeOfDay.hpp | 60 ++++++ 7 files changed, 355 insertions(+), 29 deletions(-) create mode 100644 samples/golf/src/golf/TimeOfDay.cpp create mode 100644 samples/golf/src/golf/TimeOfDay.hpp diff --git a/libsocial/include/Social.hpp b/libsocial/include/Social.hpp index 4e7598d35..3667884a5 100644 --- a/libsocial/include/Social.hpp +++ b/libsocial/include/Social.hpp @@ -247,4 +247,6 @@ class Social final static void showWebPage(const std::string&) {} static void readAllStats(); + + static bool getLatLon() { return false; } }; diff --git a/samples/golf/golf.vcxproj b/samples/golf/golf.vcxproj index 2477a532f..0a72b3541 100644 --- a/samples/golf/golf.vcxproj +++ b/samples/golf/golf.vcxproj @@ -697,6 +697,7 @@ + @@ -859,6 +860,7 @@ + diff --git a/samples/golf/golf.vcxproj.filters b/samples/golf/golf.vcxproj.filters index 410ece5b3..1c111651b 100644 --- a/samples/golf/golf.vcxproj.filters +++ b/samples/golf/golf.vcxproj.filters @@ -94,6 +94,12 @@ {4ba8aac9-a5e8-479b-b1da-bce7d195fb06} + + {53f50006-c51f-4812-b3b9-fa5904be7d82} + + + {be9dd921-53a3-46e0-a093-6cb68606eb52} + @@ -496,7 +502,10 @@ Source Files\scrub - Source Files\golf\client + Source Files\golf\client\time of day + + + Source Files\golf\client\time of day @@ -1023,10 +1032,13 @@ Header Files\scrub - Header Files\golf\client + Header Files\golf\client\time of day - Header Files + Header Files\golf\client\time of day + + + Header Files\golf\client\time of day diff --git a/samples/golf/src/golf/CMakeLists.txt b/samples/golf/src/golf/CMakeLists.txt index 50f9d2893..4252c66cf 100644 --- a/samples/golf/src/golf/CMakeLists.txt +++ b/samples/golf/src/golf/CMakeLists.txt @@ -93,6 +93,7 @@ set(GOLF_SRC ${PROJECT_DIR}/golf/TerrainChunks.cpp ${PROJECT_DIR}/golf/TerrainDepthmap.cpp ${PROJECT_DIR}/golf/TextChat.cpp + ${PROJECT_DIR}/golf/TimeOfDay.cpp ${PROJECT_DIR}/golf/TrophyDisplaySystem.cpp ${PROJECT_DIR}/golf/TrophyState.cpp ${PROJECT_DIR}/golf/TutorialDirector.cpp diff --git a/samples/golf/src/golf/MenuState.cpp b/samples/golf/src/golf/MenuState.cpp index d649122f8..05140a5fc 100644 --- a/samples/golf/src/golf/MenuState.cpp +++ b/samples/golf/src/golf/MenuState.cpp @@ -45,6 +45,7 @@ source distribution. #include "Clubs.hpp" #include "HoleData.hpp" #include "League.hpp" +#include "TimeOfDay.hpp" #include "../ErrorCheck.hpp" #include @@ -1791,40 +1792,22 @@ void MenuState::createScene() } else { - const auto hour = cro::SysTime::now().hours(); - switch (hour) + TimeOfDay tod; + auto td = tod.getTimeOfDay(); + + switch (td) { default: - case 21: - case 22: - case 23: - case 0: - case 1: - case 2: - case 3: - case 4: + case TimeOfDay::Night: propFilePath = "00.bgd"; break; - case 5: + case TimeOfDay::Morning: propFilePath = "01.bgd"; break; - case 6: - case 7: - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - case 16: - case 17: - case 18: - case 19: + case TimeOfDay::Day: propFilePath = "02.bgd"; break; - case 20: + case TimeOfDay::Evening: propFilePath = "03.bgd"; break; } diff --git a/samples/golf/src/golf/TimeOfDay.cpp b/samples/golf/src/golf/TimeOfDay.cpp new file mode 100644 index 000000000..b1ce08216 --- /dev/null +++ b/samples/golf/src/golf/TimeOfDay.cpp @@ -0,0 +1,266 @@ +/*----------------------------------------------------------------------- + +Matt Marchant 2024 +http://trederia.blogspot.com + +Super Video Golf - zlib licence. + +This software is provided 'as-is', without any express or +implied warranty.In no event will the authors be held +liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute +it freely, subject to the following restrictions : + +1. The origin of this software must not be misrepresented; +you must not claim that you wrote the original software. +If you use this software in a product, an acknowledgment +in the product documentation would be appreciated but +is not required. + +2. Altered source versions must be plainly marked as such, +and must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any +source distribution. + +-----------------------------------------------------------------------*/ + +#include "TimeOfDay.hpp" +#include "../Sunclock.hpp" +#include "../LatLong.hpp" + +#include + +#include +#include +#include + +#ifdef _WIN32 +#include +#endif + +namespace +{ + constexpr float MinLat = -90.f; + constexpr float MaxLat = -90.f; + + constexpr float MinLon = -180.f; + constexpr float MaxLon = 180.f; + + constexpr std::time_t FourWeeks = 28 * 24 * 60 * 60; + + const std::string DataFile("latlon.pos"); +} + +TimeOfDay::TimeOfDay() + : m_latlon(0.f) +{ + //attempt to read local data file + const auto path = Social::getBaseContentPath() + DataFile; + + //if file doesn't exist, refresh + if (!cro::FileSystem::fileExists(path)) + { + updateLatLon(); + } + else //if file does exist but timestamp > 28 days, refresh + { + cro::ConfigFile cfg; + if (cfg.loadFromFile(path, false)) + { + std::uint32_t ts = 0; + for (const auto& prop : cfg.getProperties()) + { + if (prop.getName() == "lat_lon") + { + m_latlon = prop.getValue(); + m_latlon.x = std::clamp(m_latlon.x, MinLat, MaxLat); + m_latlon.y = std::clamp(m_latlon.y, MinLon, MaxLon); + } + else if (prop.getName() == "timestamp") + { + ts = prop.getValue(); + } + } + + auto tsNow = std::time(nullptr); + if (ts == 0 + || ts > tsNow + || (tsNow - ts) > FourWeeks) + { + updateLatLon(); + } + } + else + { + updateLatLon(); + } + } +} + +//public +std::int32_t TimeOfDay::getTimeOfDay() const +{ + if (/*glm::length2(m_latlon) == 0*/false) + { + //take a best guess based on the system time + //I mean technically 0, 0 is valid but it's unlikely + //we're playing golf in the gulf (groan) of Guinea + const auto hour = cro::SysTime::now().hours(); + switch (hour) + { + default: + case 21: + case 22: + case 23: + case 0: + case 1: + case 2: + case 3: + case 4: + return Night; + case 5: + return Morning; + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: + case 19: + return Day; + case 20: + return Evening; + break; + } + } + else + { + //calculate the sunrise / sunset based on local time + //and our lat/lon + //sunrise / sunset is +/- 30 mins of calc'd time + //else return day or night. + auto ts = std::time(nullptr); + std::tm* gmtm = std::gmtime(&ts); + std::tm* localtm = std::localtime(&ts); + + auto hourDiff = localtm->tm_hour - gmtm->tm_hour; + auto dayDiff = localtm->tm_yday - gmtm->tm_yday; + auto yearDiff = localtm->tm_year - gmtm->tm_year; + + dayDiff -= (365 * yearDiff); //so this will be wrong on Jan 1st every 4 years... meh. + hourDiff -= (24 * dayDiff); + hourDiff = std::clamp(hourDiff, -12, 12); + + Sunclock sunclock(m_latlon.x, m_latlon.y, static_cast(hourDiff)); + + auto sunrise = sunclock.sunrise(); + auto* risetm = std::localtime(&sunrise); + + if (risetm->tm_hour == localtm->tm_hour) + { + return Morning; + } + + //LogI << "Sun rise is " << risetm->tm_hour << ":" << risetm->tm_min << std::endl; + + auto sunset = sunclock.sunset(); + auto* settm = std::localtime(&sunset); + + if (settm->tm_hour == localtm->tm_hour) + { + return Evening; + } + + //LogI << "Sun set is " << settm->tm_hour << ":" << settm->tm_min << std::endl; + + if (localtm->tm_hour > risetm->tm_hour + && localtm->tm_hour < settm->tm_hour) + { + return Day; + } + return Night; + } + + return Day; +} + +void TimeOfDay::setLatLon(glm::vec2 latlon) +{ + m_latlon = latlon; + m_latlon.x = std::clamp(m_latlon.x, MinLat, MaxLat); + m_latlon.y = std::clamp(m_latlon.y, MinLon, MaxLon); + + writeDataFile(); +} + +//private +void TimeOfDay::updateLatLon() +{ + m_latlon = { 0.f, 0.f }; + + //query web latlon - async so if we return true wait for the result message + if (!Social::getLatLon()) //webAPI for open sauce, else use steam + { + //if we failed try querying the OS + auto countryCode = getCountryCode(); + + //look up in table + if (LatLong.count(countryCode)) + { + m_latlon = LatLong.at(countryCode); + } + } + + writeDataFile(); +} + +std::string TimeOfDay::getCountryCode() +{ + std::string retVal; +#ifdef USE_GNS + //query Steam + retVal = Social::getCountryCode(); +#endif + + if (retVal.empty()) + { + //query the OS +#ifdef _WIN32 + static constexpr std::int32_t BuffSize = 8; + WCHAR buffer[BuffSize] = { 0 }; + if (auto charCount = GetUserDefaultGeoName(buffer, BuffSize); charCount == 0) + { + retVal = "US"; + } + else + { + cro::String temp = cro::String::fromUtf16(std::begin(buffer), std::begin(buffer) + charCount); + retVal = temp.toAnsiString(); + } +#else + //TODO figure out linux. + //mac... well probably toughS + retVal = "US"; +#endif + } + return retVal; +} + +void TimeOfDay::writeDataFile() const +{ + const auto path = Social::getBaseContentPath() + DataFile; + cro::ConfigFile cfg; + cfg.addProperty("lat_lon").setValue(m_latlon); + cfg.addProperty("timestamp").setValue(static_cast(std::time(nullptr))); + //cfg.save(path); //TODO enable this once we're done testing! +} \ No newline at end of file diff --git a/samples/golf/src/golf/TimeOfDay.hpp b/samples/golf/src/golf/TimeOfDay.hpp new file mode 100644 index 000000000..d00b0e84a --- /dev/null +++ b/samples/golf/src/golf/TimeOfDay.hpp @@ -0,0 +1,60 @@ +/*----------------------------------------------------------------------- + +Matt Marchant 2024 +http://trederia.blogspot.com + +Super Video Golf - zlib licence. + +This software is provided 'as-is', without any express or +implied warranty.In no event will the authors be held +liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute +it freely, subject to the following restrictions : + +1. The origin of this software must not be misrepresented; +you must not claim that you wrote the original software. +If you use this software in a product, an acknowledgment +in the product documentation would be appreciated but +is not required. + +2. Altered source versions must be plainly marked as such, +and must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any +source distribution. + +-----------------------------------------------------------------------*/ + +#pragma once + +#include + +#include +#include + +class TimeOfDay final +{ +public: + TimeOfDay(); + + enum + { + Night, Morning, + Day, Evening + }; + + std::int32_t getTimeOfDay() const; + void setLatLon(glm::vec2); + +private: + + glm::vec2 m_latlon; + + //attempts to update the lat/lon data stored on disk + void updateLatLon(); + + std::string getCountryCode(); + void writeDataFile() const; +}; \ No newline at end of file