1 /*
2  * Copyright (C) 2006-2019 Christopho, Solarus - http://www.solarus-games.org
3  *
4  * Solarus is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * Solarus is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 #include "solarus/core/CurrentQuest.h"
18 #include "solarus/core/ResourceProvider.h"
19 #include "solarus/core/QuestDatabase.h"
20 
21 namespace Solarus {
22 
23 /**
24  * \brief Creates a resource provider.
25  */
ResourceProvider()26 ResourceProvider::ResourceProvider() {
27 }
28 
29 /**
30  * \brief Preloads resources in background in a separate thread.
31  */
start_preloading_resources()32 void ResourceProvider::start_preloading_resources() {
33 
34   // Put all tilesets in the cache, without loading them yet.
35   const QuestDatabase& database = CurrentQuest::get_database();
36   const QuestDatabase::ResourceMap& tileset_ids = database.get_resource_elements(ResourceType::TILESET);
37   std::vector<std::shared_ptr<Tileset>> tilesets_to_preload;
38   for (const auto& pair : tileset_ids) {
39     const std::string& tileset_id = pair.first;
40     std::shared_ptr<Tileset> tileset = std::make_shared<Tileset>(tileset_id);
41     tileset_cache.emplace(tileset_id, tileset);
42     tilesets_to_preload.emplace_back(tileset);
43   }
44 
45   // Start loading them in a separate thread.
46   preloader_thread = std::thread([this, tilesets_to_preload]() {
47 
48     for (const std::shared_ptr<Tileset>& tileset : tilesets_to_preload) {
49       if (tileset_cache.empty()) {
50         // clear() was probably called in the meantime.
51         // No reason to continue.
52         return;
53       }
54       tileset->load();
55       std::this_thread::yield();
56     }
57   });
58 }
59 
60 /**
61  * \brief Clears all stored resources.
62  */
clear()63 void ResourceProvider::clear() {
64 
65   tileset_cache.clear();
66   preloader_thread.join();
67 }
68 
69 /**
70  * \brief Provides the tileset with the given id.
71  * \param tileset_id A tileset id.
72  * \return The corresponding tileset.
73  */
get_tileset(const std::string & tileset_id)74 Tileset& ResourceProvider::get_tileset(const std::string& tileset_id) {
75 
76   std::shared_ptr<Tileset> tileset;
77   auto it = tileset_cache.find(tileset_id);
78   if (it->second != nullptr) {
79     tileset = it->second;
80   }
81   else {
82     tileset = std::make_shared<Tileset>(tileset_id);
83     tileset_cache.emplace(tileset_id, tileset);
84   }
85 
86   tileset->load();
87 
88   return *tileset;
89 }
90 
91 /**
92  * \brief Returns all tilesets currently in cache.
93  * \return The loaded tilesets.
94  */
get_loaded_tilesets()95 const std::map<std::string, std::shared_ptr<Tileset>>& ResourceProvider::get_loaded_tilesets() {
96   return tileset_cache;
97 }
98 
99 /**
100  * \brief Notifies the resource provider that cached data (if any) is no longer valid.
101  *
102  * This function must be called when a resource element has changed on disk.
103  *
104  * \param resource_type Type of resource that has changed.
105  * \param element_id Resource element that has changed.
106  */
invalidate_resource_element(ResourceType resource_type,const std::string & element_id)107 void ResourceProvider::invalidate_resource_element(
108     ResourceType resource_type,
109     const std::string& element_id) {
110 
111   switch (resource_type) {
112 
113   case ResourceType::TILESET:
114   {
115     tileset_cache.erase(element_id);
116   }
117     break;
118 
119   default:
120     break;
121   }
122 }
123 
124 }
125