supertux
game_object_manager.hpp
1 // SuperTux
2 // Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3 // 2018 Ingo Ruhnke <grumbel@gmail.com>
4 // 2023 Vankata453
5 //
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 
19 #ifndef HEADER_SUPERTUX_SUPERTUX_GAME_OBJECT_MANAGER_HPP
20 #define HEADER_SUPERTUX_SUPERTUX_GAME_OBJECT_MANAGER_HPP
21 
22 #include "squirrel/exposable_class.hpp"
23 
24 #include <functional>
25 #include <iostream>
26 #include <typeindex>
27 #include <unordered_map>
28 #include <vector>
29 
30 #include "supertux/game_object.hpp"
31 #include "util/uid_generator.hpp"
32 
33 class DrawingContext;
34 class MovingObject;
35 class TileMap;
36 
37 template<class T> class GameObjectRange;
38 
46 {
47 public:
48  static bool s_draw_solids_only;
49 
50 public:
51  static void register_class(ssq::VM& vm);
52 
53 private:
54  struct NameResolveRequest
55  {
56  std::string name;
57  std::function<void (UID)> callback;
58  };
59 
60 public:
61  GameObjectManager(bool undo_tracking = false);
62  virtual ~GameObjectManager() override;
63 
64  virtual std::string get_exposed_class_name() const override { return "GameObjectManager"; }
65 
67  GameObject& add_object(std::unique_ptr<GameObject> object);
68  void clear_objects();
69 
70  template<typename T, typename... Args>
71  T& add(Args&&... args)
72  {
73  auto obj = std::make_unique<T>(std::forward<Args>(args)...);
74  obj->update_version();
75  T& obj_ref = *obj;
76  add_object(std::move(obj));
77  return obj_ref;
78  }
79 
80  void update(float dt_sec);
81  void draw(DrawingContext& context);
82 
83  const std::vector<std::unique_ptr<GameObject> >& get_objects() const;
84 
86  void flush_game_objects();
87 
95  void set_ambient_light(float red, float green, float blue);
104  void fade_to_ambient_light(float red, float green, float blue, float fadetime);
109  float get_ambient_red() const;
114  float get_ambient_green() const;
119  float get_ambient_blue() const;
120 
126  void set_music(const std::string& music);
127 
139  void add_object(const std::string& class_name, const std::string& name,
140  float pos_x, float pos_y, const std::string& direction,
141  const std::string& data);
142 
143  float get_width() const;
144  float get_height() const;
145  float get_editor_width() const;
146  float get_editor_height() const;
147 
149  float get_tiles_width() const;
150 
152  float get_tiles_height() const;
153 
155  virtual bool before_object_add(GameObject& object) = 0;
156 
158  virtual void before_object_remove(GameObject& object) = 0;
159 
160  template<class T>
161  GameObjectRange<T> get_objects_by_type() const
162  {
163  return GameObjectRange<T>(*this);
164  }
165 
166  const std::vector<GameObject*>&
167  get_objects_by_type_index(std::type_index type_idx) const
168  {
169  auto it = m_objects_by_type_index.find(type_idx);
170  if (it == m_objects_by_type_index.end()) {
171  // use a dummy return value to avoid making this method non-const
172  static std::vector<GameObject*> dummy;
173  return dummy;
174  } else {
175  return it->second;
176  }
177  }
178 
179  template<class T>
180  T& get_singleton_by_type() const
181  {
182  const auto& range = get_objects_by_type<T>();
183  assert(range.begin() != range.end());
184  assert(range.begin()->is_singleton());
185  return *range.begin();
186  }
187 
188  template<class T>
189  T* get_object_by_uid(const UID& uid) const
190  {
191  auto it = m_objects_by_uid.find(uid);
192  if (it == m_objects_by_uid.end())
193  {
194  // FIXME: Is this a good idea? Should gameobjects be made
195  // accessible even when not fully inserted into the manager?
196  for (auto&& itnew : m_gameobjects_new)
197  {
198  if (itnew->get_uid() == uid)
199  return static_cast<T*>(itnew.get());
200  }
201  return nullptr;
202  }
203  else
204  {
205 #ifdef NDEBUG
206  return static_cast<T*>(it->second);
207 #else
208  // Since uids should be unique, there should be no need to guess
209  // the type, thus we assert() when the object type is not what
210  // we expected.
211  auto ptr = dynamic_cast<T*>(it->second);
212  assert(ptr != nullptr);
213  return ptr;
214 #endif
215  }
216  }
217 
219  void move_object(const UID& uid, GameObjectManager& other);
220 
225  void request_name_resolve(const std::string& name, std::function<void (UID)> callback);
226 
227  template<class T>
228  T* get_object_by_name(const std::string& name) const
229  {
230  auto it = m_objects_by_name.find(name);
231  if (it == m_objects_by_name.end())
232  {
233  return nullptr;
234  }
235  else
236  {
237  return dynamic_cast<T*>(it->second);
238  }
239  }
240 
242  template<class T>
243  int get_object_count(std::function<bool(const T&)> predicate = nullptr) const
244  {
245  int total = 0;
246  for (const auto& obj : get_objects_by_type_index(typeid(T))) {
247  auto object = static_cast<T*>(obj);
248  if (object && (predicate == nullptr || predicate(*object)))
249  {
250  total += 1;
251  }
252  }
253  return total;
254  }
255 
256  const std::vector<TileMap*>& get_solid_tilemaps() const { return m_solid_tilemaps; }
257  const std::vector<TileMap*>& get_all_tilemaps() const { return m_all_tilemaps; }
258 
259  void update_solid(TileMap* solid);
260 
262  void toggle_undo_tracking(bool enabled);
263  bool undo_tracking_enabled() const { return m_undo_tracking; }
264 
266  void set_undo_stack_size(int size);
267 
269  void undo_stack_cleanup();
270 
273  void undo();
274  void redo();
275 
278  void save_object_change(GameObject& object, const std::string& data);
279 
281  void clear_undo_stack();
282 
284  bool has_object_changes() const;
285 
287  void on_editor_save();
288 
289 protected:
291  virtual MovingObject& add_object_scripting(const std::string& class_name, const std::string& name,
292  const Vector& pos, const std::string& direction,
293  const std::string& data);
294 
295  void update_tilemaps();
296 
297  void process_resolve_requests();
298 
301 
302  template<class T>
303  T* get_object_by_type() const
304  {
305  const auto& range = get_objects_by_type<T>();
306  if (range.begin() == range.end()) {
307  return nullptr;
308  } else {
309  return &*range.begin();
310  }
311  }
312 
313 private:
314  struct ObjectChange
315  {
316  std::string name;
317  UID uid;
318  std::string data;
319  bool creation; // If the change represents an object creation.
320  };
321  struct ObjectChanges
322  {
323  UID uid;
324  std::vector<ObjectChange> objects;
325  };
326 
328  void create_object_from_change(const ObjectChange& change);
329 
331  void process_object_change(ObjectChange& change);
332 
334  void save_object_change(GameObject& object, bool creation = false);
335 
336  void this_before_object_add(GameObject& object);
337  void this_before_object_remove(GameObject& object);
338 
339 protected:
342 
343 private:
344  UIDGenerator m_uid_generator;
345 
347  UIDGenerator m_change_uid_generator;
348  bool m_undo_tracking;
349  int m_undo_stack_size;
350  std::vector<ObjectChanges> m_undo_stack;
351  std::vector<ObjectChanges> m_redo_stack;
352  std::vector<ObjectChange> m_pending_change_stack; // Before a flush, any changes go here
353  UID m_last_saved_change;
354 
355  std::vector<std::unique_ptr<GameObject>> m_gameobjects;
356 
358  std::vector<std::unique_ptr<GameObject>> m_gameobjects_new;
359 
361  std::vector<TileMap*> m_solid_tilemaps;
362 
364  std::vector<TileMap*> m_all_tilemaps;
365 
366  std::unordered_map<std::string, GameObject*> m_objects_by_name;
367  std::unordered_map<UID, GameObject*> m_objects_by_uid;
368  std::unordered_map<std::type_index, std::vector<GameObject*> > m_objects_by_type_index;
369 
370  std::vector<NameResolveRequest> m_name_resolve_requests;
371 
372 private:
373  GameObjectManager(const GameObjectManager&) = delete;
374  GameObjectManager& operator=(const GameObjectManager&) = delete;
375 };
376 
377 #include "supertux/game_object_iterator.hpp"
378 
379 #endif
380 
381 /* EOF */
void on_editor_save()
Called on editor level save.
Definition: game_object_manager.cpp:374
void set_music(const std::string &music)
Sets the sector&#39;s music.
Definition: game_object_manager.cpp:554
float get_ambient_green() const
Returns the green channel of the ambient light color.
Definition: game_object_manager.cpp:542
void try_process_resolve_requests()
Same as process_resolve_requests(), but those it can&#39;t find will be kept in the buffer.
Definition: game_object_manager.cpp:94
virtual bool before_object_add(GameObject &object)=0
Hook that is called before an object is added to the vector.
Definition: game_object_iterator.hpp:96
Definition: uid_generator.hpp:22
bool has_object_changes() const
Indicate if there are any object changes in the undo stack.
Definition: game_object_manager.cpp:463
float get_tiles_height() const
returns the height (in tiles) of a worldmap
Definition: game_object_manager.cpp:612
void set_undo_stack_size(int size)
Set undo stack size.
Definition: game_object_manager.cpp:355
void undo()
Undo/redo changes to GameObjects in the manager.
Definition: game_object_manager.cpp:380
float get_ambient_blue() const
Returns the blue channel of the ambient light color.
Definition: game_object_manager.cpp:548
This class provides basic controlling functions for a sector.
Definition: game_object_manager.hpp:45
GameObject & add_object(std::unique_ptr< GameObject > object)
Queue an object up to be added to the object list.
Definition: game_object_manager.cpp:128
virtual MovingObject & add_object_scripting(const std::string &class_name, const std::string &name, const Vector &pos, const std::string &direction, const std::string &data)
Add a MovingObject from scripting.
Definition: game_object_manager.cpp:172
virtual void before_object_remove(GameObject &object)=0
Hook that is called before an object is removed from the vector.
void set_ambient_light(float red, float green, float blue)
Sets the sector&#39;s ambient light to the specified color.
Definition: game_object_manager.cpp:530
void clear_undo_stack()
Clear undo/redo stacks.
Definition: game_object_manager.cpp:455
bool m_initialized
An initial flush_game_objects() call has been initiated.
Definition: game_object_manager.hpp:341
void flush_game_objects()
Commit the queued up additions and deletions to the object list.
Definition: game_object_manager.cpp:240
void move_object(const UID &uid, GameObjectManager &other)
Move an object to another GameObjectManager.
Definition: game_object_manager.cpp:319
Definition: uid.hpp:37
void save_object_change(GameObject &object, const std::string &data)
Save object change in the undo stack with given data.
Definition: game_object_manager.cpp:448
int get_object_count(std::function< bool(const T &)> predicate=nullptr) const
Get total number of GameObjects of given type.
Definition: game_object_manager.hpp:243
This class is responsible for: Updating and drawing the object.
Definition: game_object.hpp:83
Represents a class, which can be exposed to scripting.
Definition: exposable_class.hpp:25
Base class for all dynamic/moving game objects.
Definition: moving_object.hpp:35
void request_name_resolve(const std::string &name, std::function< void(UID)> callback)
Register a callback to be called once the given name can be resolved to a UID.
Definition: game_object_manager.cpp:64
void undo_stack_cleanup()
Remove old object changes that exceed the undo stack size limit.
Definition: game_object_manager.cpp:365
This class is responsible for managing an array of tiles.
Definition: tilemap.hpp:49
void toggle_undo_tracking(bool enabled)
Toggle object change tracking for undo/redo.
Definition: game_object_manager.cpp:345
float get_ambient_red() const
Returns the red channel of the ambient light color.
Definition: game_object_manager.cpp:536
void fade_to_ambient_light(float red, float green, float blue, float fadetime)
Fades to a specified ambient light color in ""fadetime"" seconds.
Definition: game_object_manager.cpp:524
This class provides functions for drawing things on screen.
Definition: drawing_context.hpp:42
float get_tiles_width() const
returns the width (in tiles) of a worldmap
Definition: game_object_manager.cpp:600