spacebox/src/Node.hpp
Cocktail Frank 29a694200d Add sb::progress for save files, stats, and achievements
sb::progress encapsulates save progress objects, stats, and
achievements. sb::progress::Progress objects track progress using stats,
achievements, and any arbitrary user created game data. The data can be
saved and loaded through JSON serialization.

The sb::progress::Progress class is also used to unlock achievements and
update stats. They can optionally be synced directly with an app's
corresponding Stat and Achievement objects on Steam through the progress
object.

The sb::progress::Stat and sb::progress::Achievement classes represent
user defined stats and achievements. They have corresponding objects
that parse and load stats and achievements from a config file.

Other changes include:

JSON/Configuration:

- Upgrade nlohmann::json to v3.11.3

- Use nlohmann::json::merge_patch to merge JSON into configuration, which
  provides recursive merge

- Move json_from_file from Configuration to sb:: since it was already
  static and provides general access to a JSON object

- Move Configuration into sb:: namespace

- Move Configuration::access into sb::json_access to share with Progress
  class

Steam API:

- Automatically request stats when Steam API is initialized

- Add responses for events to Steam API event loop: UserStatsReceived,
  UserStatsStored, UserAchievementStored

- Add call for storing stats on Steam's servers

- Add publicly accessible boolean that controls whether or not sb::init
  tries to load Steam

Testing:

- Capture log messages with stdout in the test program before logging is
  initialized in the Game object

- In test cases that run a game, record start time within the mainloop
  to prevent the start time from lagging when the game takes a while to
  start running

- New tests: sb::progress, sb::json_access, setting stats and
  achievements with the Steam API

- Add another Dockerized Ubuntu build launching that launches the test
  on the container after it is built

Bug fix:

- Remove PostMix processor when Recorder object is destroyed to prevent
  the processor function (which doesn't exist anymore) from being called

Linting:

- superxbr.cpp, Delegate.hpp
2024-10-05 20:43:48 -04:00

120 lines
3.0 KiB
C++

/* +------------------------------------------------------+
____/ \____ /| - Open source game framework licensed to freely use, |
\ / / | copy, modify and sell without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - created for <https://foam.shampoo.ooo> |
| ~~~~~~~~~~~~ | +------------------------------------------------------+
| SPACE ~~~~~ | /
| ~~~~~~~ BOX |/
+--------------+
@deprecated The Node class will be completely removed in a future update. The original intention of the framework was
for every class to inherit the Node class, automatically creating a graph of game objects that allowed each object to
access any other game object. In practice, it seems better to let the implementation decide if it wants to use that
pattern with some, none, or all objects, using either its own wrapper class or a future Node class designed with the
intention of being optional. This will also allow for other patterns like Entity Component System to be used.
*/
#pragma once
#include <string>
#include <iostream>
#include "glm/vec2.hpp"
#include "json/json.hpp"
#include "SDL.h"
#include "Log.hpp"
#include "filesystem.hpp"
class Game;
namespace sb
{
class Delegate;
}
class Input;
class Box;
namespace sb
{
class Configuration;
}
struct Audio;
namespace sb
{
class Display;
}
/*!
* @deprecated Use an alternative to this class if possible because it will be removed soon. Global access to functionality in
* this class should instead go through the Game class directly.
*/
class Node
{
public:
Node();
Node(Node*);
void set_parent(Node*);
virtual void reset() { deactivate(); }
virtual void activate() { active = true; }
virtual void deactivate() { active = false; }
bool is_active() const;
const sb::Configuration& configuration() const;
sb::Configuration& configuration();
/*!
* @return const reference to the Delegate object
*/
const sb::Delegate& delegate() const;
/*!
* @return the Delegate object
*/
sb::Delegate& delegate();
/*!
* @deprecated use Node::delegate
*/
sb::Delegate& get_delegate();
const sb::Display& get_display() const;
const std::shared_ptr<SDL_Window> window() const;
std::shared_ptr<SDL_Window> window();
const Game* get_root() const;
Box window_box(bool = false);
const std::string get_branch_as_string() const;
virtual std::string class_name() const { return "Node"; };
virtual ~Node();
template<typename T = Game>
T* get_root()
{
if (parent == nullptr)
{
return static_cast<T*>(this);
}
else
{
return parent->get_root<T>();
}
}
private:
Node* parent;
bool active = true;
};
/* Add Node class to the sb namespace. This should be the default location, but Node is left in the global namespace
* for backward compatibility. */
namespace sb
{
using ::Node;
}