HighScoreManager.cxx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. #include "HighScoreManager.hxx"
  2. #include <SDL.h>
  3. #include <algorithm>
  4. #include <filesystem>
  5. #include <fstream>
  6. #include <numeric>
  7. namespace fs = std::filesystem;
  8. HighScoreManager::HighScoreManager()
  9. {
  10. data_dir_ = SDL_GetPrefPath("draconic-bytes", "snake");
  11. fs::create_directories(data_dir_);
  12. load();
  13. }
  14. void HighScoreManager::load()
  15. {
  16. auto const filename = fs::path{data_dir_}/"highscore.dat";
  17. std::ifstream input{filename, std::ios::binary};
  18. if (!input) {
  19. SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Missing high score file: %s", filename.c_str());
  20. return;
  21. }
  22. std::size_t count;
  23. input.read(std::bit_cast<char*>(&count), sizeof(std::size_t));
  24. high_score_.scores_.resize(count);
  25. for (std::size_t n = 0; n<count; ++n) {
  26. std::size_t len;
  27. input.read(std::bit_cast<char*>(&len), sizeof(std::size_t));
  28. high_score_.scores_[n].player_name_.resize(len);
  29. input.read(high_score_.scores_[n].player_name_.data(), static_cast<std::streamsize>(len));
  30. input.read(std::bit_cast<char*>(&(high_score_.scores_[n].points_)), sizeof(unsigned));
  31. }
  32. std::ranges::stable_sort(high_score_.scores_, std::greater<>{}, &Score::points_);
  33. if (high_score_.scores_.empty()) {
  34. SDL_Log("No existing high scores.");
  35. }
  36. else {
  37. SDL_Log("Loaded high scores:");
  38. for (auto const& score: high_score_.scores_) {
  39. SDL_Log(" - %s: %u", score.player_name_.c_str(), score.points_);
  40. }
  41. }
  42. }
  43. void HighScoreManager::save() const
  44. {
  45. auto const filename = fs::path{data_dir_}/"highscore.dat";
  46. std::ofstream output{filename, std::ios::binary};
  47. if (!output) {
  48. SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed saving high scores to file %s", filename.c_str());
  49. return;
  50. }
  51. auto const count = high_score_.scores_.size();
  52. output.write(std::bit_cast<char const*>(&count), sizeof(std::size_t));
  53. for (auto const& score: high_score_.scores_) {
  54. auto const len = score.player_name_.length();
  55. output.write(std::bit_cast<char const*>(&len), sizeof(std::size_t));
  56. output.write(score.player_name_.data(), static_cast<std::streamsize>(score.player_name_.length()));
  57. output.write(std::bit_cast<char const*>(&score.points_), sizeof(unsigned));
  58. }
  59. if (high_score_.scores_.empty()) {
  60. SDL_Log("No high scores saved.");
  61. }
  62. else {
  63. SDL_Log("Saved high scores:");
  64. for (auto const& score: high_score_.scores_) {
  65. SDL_Log(" - %s: %u", score.player_name_.c_str(), score.points_);
  66. }
  67. }
  68. }
  69. void HighScoreManager::set_new_score(unsigned int score)
  70. {
  71. if (high_score_.scores_.size()<MAX_SCORES || high_score_.scores_.back().points_<score) {
  72. new_score_ = score;
  73. }
  74. else {
  75. new_score_.reset();
  76. }
  77. }
  78. bool HighScoreManager::has_new_score() const
  79. {
  80. return new_score_.has_value();
  81. }
  82. unsigned HighScoreManager::get_new_score() const
  83. {
  84. return new_score_.value_or(0u);
  85. }
  86. void HighScoreManager::provide_name_for_new_score(std::string const& name)
  87. {
  88. if (new_score_.has_value()) {
  89. high_score_.scores_.push_back({name, new_score_.value()});
  90. new_score_.reset();
  91. std::ranges::stable_sort(high_score_.scores_, std::greater<>{}, &Score::points_);
  92. if (high_score_.scores_.size()>MAX_SCORES) {
  93. high_score_.scores_.resize(MAX_SCORES);
  94. }
  95. save();
  96. }
  97. }
  98. HighScoreManager& HighScoreManager::instance()
  99. {
  100. static HighScoreManager manager;
  101. return manager;
  102. }
  103. std::vector<Score> const& HighScoreManager::get_scores() const
  104. {
  105. return high_score_.scores_;
  106. }