Add persistent AFK reserves for both engines (Refs #12)
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace utils::afk
|
||||
{
|
||||
struct request { std::string id, action, body; };
|
||||
struct session
|
||||
{
|
||||
std::string body, phase;
|
||||
int authorized_seconds = 0, consumed_seconds = 0;
|
||||
};
|
||||
struct acknowledgement
|
||||
{
|
||||
bool valid = false;
|
||||
std::string reason = "schema", state, code, id, session_id;
|
||||
int free_seconds = 0, saved_seconds = 0, available_seconds = 0,
|
||||
reserved_seconds = 0, capacity_seconds = 0, authorized_seconds = 0,
|
||||
bank_balance = 0, purchase_points = 0, purchase_seconds = 0,
|
||||
max_purchase_packs = 0, awarded_seconds = 0, consumed_seconds = -1;
|
||||
};
|
||||
acknowledgement parse_acknowledgement(const std::string& response);
|
||||
// Single game-thread writer. Active clocks are process-local, so recovery
|
||||
// can never accidentally replay protection after a process restart.
|
||||
class journal
|
||||
{
|
||||
public:
|
||||
using clock = std::chrono::steady_clock;
|
||||
journal(std::filesystem::path root, std::string server, std::string endpoint);
|
||||
std::vector<request> load() const;
|
||||
void store(const std::string& body) const;
|
||||
void erase(const std::string& id) const;
|
||||
void prepare(const std::string& reserve_body) const;
|
||||
void authorize(const std::string& id, int seconds) const;
|
||||
void begin(const std::string& id, clock::time_point now = clock::time_point{}) const;
|
||||
int checkpoint(const std::string& id, clock::time_point now = clock::now()) const;
|
||||
// Hot path for the damage hook/countdown: no disk I/O or clock reset.
|
||||
// Missing/restarted clocks return -1; stopped/expired clocks return 0.
|
||||
int remaining(const std::string& id, clock::time_point now = clock::now()) const;
|
||||
void stop(const std::string& id, const std::string& reason, clock::time_point now = clock::now()) const;
|
||||
// Call only at map initialization, with its new persistent match ID.
|
||||
// Active current-map sessions are rejected. Unknown crash intervals
|
||||
// remain unresolved at EC, rather than refunding spendable authority.
|
||||
void recover(const std::string& current_match) const;
|
||||
private:
|
||||
struct snapshot { std::vector<request> requests; std::vector<session> sessions; };
|
||||
std::filesystem::path file_;
|
||||
std::string server_, endpoint_, scope_;
|
||||
request decode(const std::string& body) const;
|
||||
snapshot read() const;
|
||||
void save(const snapshot& value) const;
|
||||
std::string key(const std::string& id) const;
|
||||
int elapsed(const session& value, clock::time_point now, bool round_up = false) const;
|
||||
request settlement(const session& value, const std::string& reason, int consumed) const;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user