mirror of
https://github.com/Dingo-Shenanigans/ReSkate.git
synced 2026-10-18 00:27:06 +02:00
Map updates - A map the game already has, being replaced by the host's version, could load as soon as the new files were in Mods, while the mods were still being applied: it ended on "This map is not loading". The session now holds the load while a map is downloading, installing or applying, as it waits for one that is missing. - A player whose version of a map is later than the host's keeps it and loads. Only an older one is replaced by the host's. Versions are compared number by number (1.10.0 is later than 1.9.2). Dedicated servers - maps.latest_versions (off by default): the server asks Thunderstore for the newest version of each of its custom maps, at start and every maps.latest_check_minutes (5-1440, default 60), and writes it into the mod's manifest.json. Nothing is downloaded: the server reads only a map's level list and version, and players, who are held to the server's version, fetch it as they join. The map being played waits until nobody is on it. A folder that is not a Thunderstore package is not touched, and the level list is left as it is. - Console: maps update, maps latest on|off, maps latest every <minutes>. Overlay - Vote card: the pass mark is always in the middle of the bar. Green grows over the left half up to the yes votes needed and over the right half past them, whatever share the vote needs. - The "Staff" tag is "ReSkate Admin", shimmering from #2500FF to #B2F9FF. No protocol change. Tests cover the version comparison and the manifest write; the Thunderstore lookup was checked against the site. The map update flow, the vote bar and the tag were not seen in game, and the server setting has not run on a live server. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
52 lines
2.6 KiB
C++
52 lines
2.6 KiB
C++
#pragma once
|
|
#include <chrono>
|
|
#include <filesystem>
|
|
#include <future>
|
|
#include <set>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
// Keeping the server's custom maps at their newest Thunderstore version ("maps.latest_versions").
|
|
// The server reads two files of a map mod: reskate-levels.json (its levels) and manifest.json
|
|
// (its version, which players are held to: protocol.h: map_package_name). So nothing is
|
|
// downloaded: a map mod in Mods whose folder is a Thunderstore package (Owner-Name) is asked
|
|
// about, and when Thunderstore's newest version is not the one in its manifest.json, that
|
|
// version is written there. Players then fetch the newest as they join.
|
|
//
|
|
// The level list is left as it is. A new version that adds, removes or renames levels needs its
|
|
// reskate-levels.json copied in by the server's owner, as when the map was first set up.
|
|
namespace dingosdk::server {
|
|
struct MapUpdate {
|
|
std::string folder, from, to; // the mod folder, its version before and Thunderstore's newest
|
|
bool updated{}; // the newest version is in its manifest.json
|
|
bool waiting{}; // left for later: its map is being played
|
|
std::string problem; // why it could not be looked up or written, or empty
|
|
};
|
|
// Looks every map mod in `mods` up and writes the newest version where it differs. `in_play`: a
|
|
// mod folder to leave as it is this time. Asks Thunderstore, so it can take a few seconds a
|
|
// map; made for a worker thread.
|
|
std::vector<MapUpdate> update_maps(const std::filesystem::path &mods, const std::string &in_play);
|
|
// The version a mod folder's manifest.json gives (nothing when it has none), and writing one
|
|
// there: everything else in the file is kept, and a folder without one gets a file with the
|
|
// version alone. Throws when the file cannot be written.
|
|
std::string map_version(const std::filesystem::path &mod);
|
|
void set_map_version(const std::filesystem::path &mod, const std::string &version);
|
|
|
|
// The run loop's side: a check when one is due or asked for, on a worker, and what it found.
|
|
class MapUpdater {
|
|
public:
|
|
struct Done {
|
|
std::vector<std::string> lines; // for the log
|
|
bool changed{}; // a map's version changed: read Mods again
|
|
};
|
|
// Every turn of the loop. `enabled` and `minutes`: the config's; `asked`: "maps update".
|
|
Done tick(bool enabled, unsigned minutes, const std::filesystem::path &mods, const std::string &in_play, bool asked);
|
|
|
|
private:
|
|
std::future<std::vector<MapUpdate>> work_;
|
|
std::chrono::steady_clock::time_point next_{};
|
|
bool asked_{};
|
|
std::set<std::string> said_; // problems said once, not at every check
|
|
};
|
|
} // namespace dingosdk::server
|