CConfigHandler.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /*
  2. * CConfigHandler.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "CConfigHandler.h"
  12. #include "../lib/filesystem/Filesystem.h"
  13. #include "../lib/filesystem/FileStream.h"
  14. #include "../lib/GameConstants.h"
  15. #include "../lib/VCMIDirs.h"
  16. VCMI_LIB_NAMESPACE_BEGIN
  17. SettingsStorage settings;
  18. template<typename Accessor>
  19. SettingsStorage::NodeAccessor<Accessor>::NodeAccessor(SettingsStorage & _parent, std::vector<std::string> _path):
  20. parent(_parent),
  21. path(std::move(_path))
  22. {
  23. }
  24. template<typename Accessor>
  25. SettingsStorage::NodeAccessor<Accessor> SettingsStorage::NodeAccessor<Accessor>::operator[](const std::string & nextNode) const
  26. {
  27. std::vector<std::string> newPath = path;
  28. newPath.push_back(nextNode);
  29. return NodeAccessor(parent, newPath);
  30. }
  31. template<typename Accessor>
  32. SettingsStorage::NodeAccessor<Accessor>::operator Accessor() const
  33. {
  34. return Accessor(parent, path);
  35. }
  36. template<typename Accessor>
  37. SettingsStorage::NodeAccessor<Accessor> SettingsStorage::NodeAccessor<Accessor>::operator () (std::vector<std::string> _path) const
  38. {
  39. std::vector<std::string> newPath = path;
  40. newPath.insert( newPath.end(), _path.begin(), _path.end());
  41. return NodeAccessor(parent, newPath);
  42. }
  43. SettingsStorage::SettingsStorage():
  44. write(NodeAccessor<Settings>(*this, std::vector<std::string>() )),
  45. listen(NodeAccessor<SettingsListener>(*this, std::vector<std::string>() ))
  46. {
  47. }
  48. void SettingsStorage::init()
  49. {
  50. std::string confName = "config/settings.json";
  51. JsonUtils::assembleFromFiles(confName).swap(config);
  52. // Probably new install. Create config file to save settings to
  53. if (!CResourceHandler::get("local")->existsResource(ResourceID(confName)))
  54. CResourceHandler::get("local")->createResource(confName);
  55. JsonUtils::maximize(config, "vcmi:settings");
  56. JsonUtils::validate(config, "vcmi:settings", "settings");
  57. }
  58. void SettingsStorage::invalidateNode(const std::vector<std::string> &changedPath)
  59. {
  60. for(SettingsListener * listener : listeners)
  61. listener->nodeInvalidated(changedPath);
  62. JsonNode savedConf = config;
  63. savedConf.Struct().erase("session");
  64. JsonUtils::minimize(savedConf, "vcmi:settings");
  65. FileStream file(*CResourceHandler::get()->getResourceName(ResourceID("config/settings.json")), std::ofstream::out | std::ofstream::trunc);
  66. file << savedConf.toJson();
  67. }
  68. JsonNode & SettingsStorage::getNode(const std::vector<std::string> & path)
  69. {
  70. JsonNode *node = &config;
  71. for(const std::string & value : path)
  72. node = &(*node)[value];
  73. return *node;
  74. }
  75. Settings SettingsStorage::get(const std::vector<std::string> & path)
  76. {
  77. return Settings(*this, path);
  78. }
  79. const JsonNode & SettingsStorage::operator[](const std::string & value) const
  80. {
  81. return config[value];
  82. }
  83. const JsonNode & SettingsStorage::toJsonNode() const
  84. {
  85. return config;
  86. }
  87. SettingsListener::SettingsListener(SettingsStorage & _parent, std::vector<std::string> _path):
  88. parent(_parent),
  89. path(std::move(_path))
  90. {
  91. parent.listeners.insert(this);
  92. }
  93. SettingsListener::SettingsListener(const SettingsListener &sl):
  94. parent(sl.parent),
  95. path(sl.path),
  96. callback(sl.callback)
  97. {
  98. parent.listeners.insert(this);
  99. }
  100. SettingsListener::~SettingsListener()
  101. {
  102. parent.listeners.erase(this);
  103. }
  104. void SettingsListener::nodeInvalidated(const std::vector<std::string> &changedPath)
  105. {
  106. if (!callback)
  107. return;
  108. size_t min = std::min(path.size(), changedPath.size());
  109. size_t mismatch = std::mismatch(path.begin(), path.begin()+min, changedPath.begin()).first - path.begin();
  110. if (min == mismatch)
  111. callback(parent.getNode(path));
  112. }
  113. void SettingsListener::operator() (std::function<void(const JsonNode&)> _callback)
  114. {
  115. callback = std::move(_callback);
  116. }
  117. Settings::Settings(SettingsStorage &_parent, const std::vector<std::string> &_path):
  118. parent(_parent),
  119. path(_path),
  120. node(_parent.getNode(_path)),
  121. copy(_parent.getNode(_path))
  122. {
  123. }
  124. Settings::~Settings()
  125. {
  126. if (node != copy)
  127. parent.invalidateNode(path);
  128. }
  129. JsonNode* Settings::operator -> ()
  130. {
  131. return &node;
  132. }
  133. const JsonNode* Settings::operator ->() const
  134. {
  135. return &node;
  136. }
  137. const JsonNode & Settings::operator[](const std::string & value) const
  138. {
  139. return node[value];
  140. }
  141. JsonNode & Settings::operator[](const std::string & value)
  142. {
  143. return node[value];
  144. }
  145. // Force instantiation of the SettingsStorage::NodeAccessor class template.
  146. // That way method definitions can sit in the cpp file
  147. template struct SettingsStorage::NodeAccessor<SettingsListener>;
  148. template struct SettingsStorage::NodeAccessor<Settings>;
  149. VCMI_LIB_NAMESPACE_END