Launcher: mod profiles, sharing them by code or file, and Thunderstore dependencies

The Mods page has a third tab, PROFILES. A profile is a saved list of which
mods are on, in what order and at what version; every mod stays installed
once, in the one Mods folder. Loading a profile rewrites mods.json, switches
off what it does not name, and downloads from Thunderstore what it names
that is missing. Profiles live in Mods/profiles.json.

A profile travels the way r2modman's do, so the two managers read each
other's: export.r2x inside a .r2z file, and a code on Thunderstore's
profile service. Config files in an r2modman profile are ignored.

Installing or updating a Thunderstore package now brings the packages it
depends on, needed ones first, leaving out any already installed at a new
enough version. A mod pack is a package that is nothing else.

A kick, by an admin or by a passed vote, used to keep the player out until
the server restarted. "kick_minutes" in the players section of the config
(1-1440; 0, the default, is still until the restart) and the console
command "kick-time <minutes>|restart" now set how long it lasts.

The player is told how long when they are kicked, and how many minutes are
left if they try to join early. A kick keeps the time it was given, so
changing the setting is for later kicks. Bans are unchanged.
This commit is contained in:
AyeZeeBB committed 2026-10-13 00:55:29 -05:00
1 parent 242ac11814
commit 2e186b9839
24 files changed
+1488 -38

No files matched your search

+20 -4
View File
@@ -16,7 +16,7 @@
namespace dingosdk::server {
namespace {
constexpr std::string_view help_text =
"status | net [player] | players | say <text> | msg <player> <text> | msg-party <player> <text> | msg-admins <text> | kick <player> | ban <player or SteamID64> [name] | unban <SteamID64> | bans\n"
"status | net [player] | players | say <text> | msg <player> <text> | msg-party <player> <text> | msg-admins <text> | kick <player> | kick-time <minutes>|restart | ban <player or SteamID64> [name] | unban <SteamID64> | bans\n"
"map <name, e.g. San Vansterdam> | maps [reload] | name <text> | password <text|off> | welcome <text|off> | listed on|off\n"
"voice on|off | voice-range <50-1000> | distances <full> <half> <half-return> <low> | crowd <n>|off | rate <KB/s> | bone-scale <1-8>|off | bone-reach <0.5-20>|off\n"
"placement everyone|admins|nobody | objects <number>|off | object-scaling on|off | effects on|off | clear-objects | noclip on|off | nobail on|off | boosts on|off | tuning on|off\n"
@@ -132,9 +132,20 @@ std::string Host::command(std::string_view line, std::uint64_t admin) {
if (!guest || !guest->handshaken) return "No single connected player matches \"" + std::string(argument) + "\".";
if (!outranks(guest->member.id)) return "You cannot kick a player of your rank or above.";
const auto label = guest_name(*guest);
kicked_.insert(guest->member.id);
drop(guest->member.id, "You were kicked from this server.");
return changed(label + " was kicked until the server restarts.");
const auto how_long = keep_out(guest->member.id);
drop(guest->member.id, "You were kicked from this server" + how_long + ".");
return changed(label + " was kicked" + how_long + ".");
}
if (name == "kick-time") {
const auto word = lower(argument);
const auto value = word == "restart" || word == "off" ? std::optional<std::uint64_t>(0) : number(argument);
if (!value || *value > 1440)
return "kick-time <minutes 1-1440>|restart (now " +
(config_.kick_minutes ? std::to_string(config_.kick_minutes) + " min" : std::string("until the server restarts")) + ")";
config_.kick_minutes = static_cast<unsigned>(*value);
return changed(config_.kick_minutes
? "Kicked players can join again after " + std::to_string(config_.kick_minutes) + " min. Players already kicked keep the time they were given."
: std::string("Kicked players stay out until the server restarts. Players already kicked keep the time they were given."));
}
if (name == "ban") {
auto [who, reason] = split(argument);
@@ -950,6 +961,11 @@ void Host::check_scoring(Guest &guest) {
// time. Flagged players are taken out of linked throwdowns and coop challenges (the roster's
// speeding flag: every client drops them from those), or kicked; the flag clears after a minute
// of normal speed.
std::string Host::keep_out(std::uint64_t id) {
const auto minutes = config_.kick_minutes;
kicked_[id] = minutes ? now_ + minutes * 60000000ULL : 0;
return minutes ? " for " + std::to_string(minutes) + (minutes == 1 ? " minute" : " minutes") : std::string(" until the server restarts");
}
bool Host::check_speed(Guest &guest, std::uint64_t sent) {
if (config_.speed_check == "off" || !guest.handshaken || !guest.world_ready || !sent) return true;
if (!guest.speed.sample(sent, now_)) return true;