mirror of
https://github.com/Dingo-Shenanigans/ReSkate.git
synced 2026-10-18 02:47:01 +02:00
Server: object scaling can be turned off
Server: object scaling can be turned off A dedicated server can stop players resizing the objects they place. - "allow_object_scaling" in the config's "players" section (default true), and "object-scaling on|off" from the console or an admin. A change is saved and applies at once. - Off: the server shares every player's objects at their own size, whatever that player's game sent. Admins can still resize theirs, as with the object limit. - The roster tells each game. In the park editor of a player on such a server the SCALE mode is not offered, its Y shortcut does nothing, the scale box is disabled with a note saying why, and what is placed or edited is its own size. - An object resized before the setting was turned off is its own size for everyone else straight away; its owner sees it resized until they edit it.
This commit is contained in:
1 parent
c8c6cf16f2
commit
9ab985e778
19 files changed
+1625
-1606
No files matched your search
@@ -153,6 +153,9 @@ struct MultiplayerModel {
|
||||
// Objects each player may have placed in this session (0: no limit), the limit this
|
||||
// player is held to (0 for the host and a server's admins), and how many they have placed.
|
||||
unsigned object_limit{}, object_limit_own{}, objects_placed{};
|
||||
// This player may resize the objects they place (a dedicated server can turn it off for its
|
||||
// players; its admins always may).
|
||||
bool object_scaling{true};
|
||||
// Host setting: whether guests may use noclip / No Bail (the host and server admins always may).
|
||||
bool guest_noclip{true}, guest_no_bail{true}, guest_boosts{true};
|
||||
// Host setting: guests skate with the host's physics tuning (on a dedicated server: the
|
||||
|
||||
@@ -619,6 +619,7 @@ std::vector<std::uint8_t> encode(const Packet &p, bool compact_pose, std::uint32
|
||||
w.integer(static_cast<std::uint8_t>(p.object_placement), 1);
|
||||
if (!valid_object_limit(p.object_limit)) throw std::invalid_argument("Invalid object limit");
|
||||
w.integer(p.object_limit, 2);
|
||||
w.integer(p.object_scaling ? 1 : 0, 1);
|
||||
w.integer(p.force_world_layers, 1);
|
||||
// One mode per world-layer catalog row; both peers read the same catalog
|
||||
// from the same game build.
|
||||
@@ -945,6 +946,9 @@ std::optional<Packet> decode(std::span<const std::uint8_t> bytes) noexcept {
|
||||
const auto object_limit = r.integer(2);
|
||||
if (!valid_object_limit(object_limit)) return {};
|
||||
p.object_limit = static_cast<unsigned>(object_limit);
|
||||
const auto scaling = r.integer(1);
|
||||
if (scaling > 1) return {};
|
||||
p.object_scaling = scaling != 0;
|
||||
const auto forced = r.integer(1);
|
||||
if (forced > 1) return {};
|
||||
p.force_world_layers = forced != 0;
|
||||
|
||||
@@ -188,6 +188,9 @@ struct Packet {
|
||||
ObjectPlacement object_placement = ObjectPlacement::everyone;
|
||||
// Objects each player may have placed (object_placement.h); 0: no limit.
|
||||
unsigned object_limit{};
|
||||
// Roster: players may place objects at another size than their own. Off: a dedicated server
|
||||
// shares every player's objects at their own size (its admins' excepted).
|
||||
bool object_scaling{true};
|
||||
// Bumped each time the host deletes all guest objects. Guests delete their
|
||||
// own session objects when it changes after their first roster.
|
||||
std::uint32_t object_clears{};
|
||||
|
||||
@@ -74,6 +74,7 @@ void stop(Session &s, std::string reason) {
|
||||
s.tps = multiplayer_default_tps;
|
||||
s.object_placement = ObjectPlacement::everyone;
|
||||
s.object_limit = 0;
|
||||
s.object_scaling = true;
|
||||
set_lobby_object_limit(0);
|
||||
s.server_admin = false;
|
||||
s.server_bans.clear();
|
||||
|
||||
@@ -155,6 +155,7 @@ struct Session {
|
||||
MultiplayerDistances distances;
|
||||
ObjectPlacement object_placement = ObjectPlacement::everyone;
|
||||
unsigned object_limit{}; // objects each player may have placed; 0: no limit
|
||||
bool object_scaling{true}; // the dedicated server lets players resize what they place
|
||||
// What guests may use: the host's choice, or the host's roster for a guest.
|
||||
bool guest_noclip = true, guest_no_bail = true, guest_boosts = true;
|
||||
// Host: guests skate with its physics tuning. Guest: the host's roster says so (a
|
||||
|
||||
@@ -273,6 +273,7 @@ void apply_roster(Session &s, const Packet &p, std::uint64_t now) {
|
||||
}
|
||||
apply_object_placement(s, p.object_placement);
|
||||
apply_object_limit(s, p.object_limit); // after server_admin, which exempts an admin
|
||||
s.object_scaling = !dedicated_host(s) || p.object_scaling;
|
||||
apply_guest_tools(s, p.guest_noclip, p.guest_no_bail, p.guest_boosts);
|
||||
s.enforce_tuning = p.enforce_tuning;
|
||||
s.server_votes = dedicated_host(s) ? p.server_votes : 0;
|
||||
|
||||
@@ -151,6 +151,7 @@ void publish(Session &s, const NativeFrame *local) {
|
||||
view.distances = s.distances;
|
||||
view.object_placement = s.object_placement;
|
||||
view.object_limit = s.object_limit;
|
||||
view.object_scaling = s.object_scaling || s.server_admin || s.mode != Mode::join;
|
||||
view.object_limit_own = s.mode == Mode::host || s.server_admin ? 0 : s.object_limit; // as apply_object_limit gives this game
|
||||
view.objects_placed = s.mode == Mode::off ? 0 : static_cast<unsigned>(s.local_objects.objects().size());
|
||||
view.guest_noclip = s.guest_noclip;
|
||||
|
||||
@@ -585,6 +585,9 @@ void object_codec() {
|
||||
const auto listed = decode(encode(served));
|
||||
check(listed && listed->members.size() == 34 && listed->capacity == 32, "A server's roster past its limit failed to round-trip");
|
||||
check(listed && listed->vote == served.vote, "A server's vote failed to round-trip");
|
||||
served.object_scaling = false;
|
||||
const auto fixed = decode(encode(served));
|
||||
check(fixed && !fixed->object_scaling && listed && listed->object_scaling, "The roster's object scaling rule failed to round-trip");
|
||||
served.vote = {};
|
||||
const auto quiet = decode(encode(served));
|
||||
check(quiet && quiet->vote == ServerVote{}, "A roster without a vote did not come back without one");
|
||||
|
||||
@@ -120,6 +120,13 @@ bool draw_park_editor(ParkEditorUI &ui, const Model &model, const CallbacksV3 &c
|
||||
} else
|
||||
leave(ui, callbacks, visible, escape_closes); // Esc goes straight back to the game
|
||||
}
|
||||
// A server that has turned object scaling off shares everything at its own size: nothing is
|
||||
// resized here either, so what this player sees is what everyone else does.
|
||||
ui.scaling_allowed = model.multiplayer.object_scaling;
|
||||
if (!ui.scaling_allowed) {
|
||||
ui.scale = 1;
|
||||
if (ui.mode == ParkTransformMode::scale) ui.mode = ParkTransformMode::move;
|
||||
}
|
||||
namespace skate = dingosdk::skate_theme;
|
||||
const float k = std::clamp(ui.ui_scale, .5f, 3.0f);
|
||||
const auto P = [k](float value) { return value * k; };
|
||||
@@ -216,6 +223,7 @@ bool draw_park_editor(ParkEditorUI &ui, const Model &model, const CallbacksV3 &c
|
||||
for (std::size_t i = 0; i < modes.size(); ++i) {
|
||||
if (i)
|
||||
ImGui::SameLine(0, P(6));
|
||||
if (modes[i].second == ParkTransformMode::scale && !ui.scaling_allowed) continue; // the server has it off
|
||||
if (mode_tile(frame, bold_font, modes[i].first, ui.mode == modes[i].second, k, static_cast<unsigned>(41 + i))) {
|
||||
ui.mode = modes[i].second;
|
||||
ui.dragging = -1;
|
||||
@@ -493,7 +501,7 @@ bool draw_park_editor(ParkEditorUI &ui, const Model &model, const CallbacksV3 &c
|
||||
ui.mode = ParkTransformMode::move;
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_R, false))
|
||||
ui.mode = ParkTransformMode::rotate;
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_Y, false))
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_Y, false) && ui.scaling_allowed)
|
||||
ui.mode = ParkTransformMode::scale;
|
||||
}
|
||||
if (io.KeyCtrl && ImGui::IsKeyPressed(ImGuiKey_C, false))
|
||||
|
||||
@@ -18,6 +18,7 @@ struct ParkEditorUI {
|
||||
std::string category, placing, feedback, queued_status;
|
||||
editor::Vec3 position{}, angles{}, drag_start{}, drag_axis{};
|
||||
editor::Quat drag_rotation{0, 0, 0, 1};
|
||||
bool scaling_allowed{true}; // off: the server shares objects at their own size, so none is resized here
|
||||
float scale{1}, grid{.5f}, angle_snap{15}, scale_snap{.1f}, plane_height{}, distance{10},
|
||||
drag_parameter{}, drag_angle{}, drag_scale{1}, drag_gizmo_scale{1};
|
||||
ParkTransformMode mode{ParkTransformMode::move};
|
||||
|
||||
@@ -194,9 +194,12 @@ void inspector(ParkEditorUI &ui, const Model &model, const CallbacksV3 &callback
|
||||
ui.inspector_dirty = true;
|
||||
ImGui::TextUnformatted(ui.selection.size() > 1 ? "Scale multiplier" : "Uniform scale");
|
||||
ImGui::SetNextItemWidth(-1);
|
||||
ImGui::BeginDisabled(!ui.scaling_allowed);
|
||||
if (ImGui::DragFloat("##scale", &ui.scale, .01f, .01f, 100, "%.3f",
|
||||
ImGuiSliderFlags_AlwaysClamp))
|
||||
ui.inspector_dirty = true;
|
||||
ImGui::EndDisabled();
|
||||
if (!ui.scaling_allowed) ImGui::TextDisabled("This server has object scaling off.");
|
||||
ImGui::BeginDisabled(!selected && ui.surface_mode && !ui.surface_valid && !ui.inspector_dirty);
|
||||
skate_theme::push_primary_button();
|
||||
ImGui::PushFont(font_or(ui.bold_font));
|
||||
|
||||
@@ -121,6 +121,11 @@ object_placement everyone, admins (only admins can build), or nobody.
|
||||
object_limit How many objects each player may have placed, 1-1024
|
||||
(default 100), or 0 for no limit. Admins are not limited.
|
||||
A player at the limit deletes one to place another.
|
||||
allow_object_scaling Let players place objects bigger or smaller than their
|
||||
own size (default true). false shares every player's
|
||||
objects at their own size and turns the size controls
|
||||
off in their park editor. Admins can still resize
|
||||
theirs. Console: object-scaling on|off.
|
||||
announce_throwdowns Tell everyone in chat when a throwdown drop is placed
|
||||
(default true).
|
||||
|
||||
@@ -266,6 +271,7 @@ and change voice, distances, placement and kicks from the Multiplayer menu.
|
||||
distances <full> <half> <half-return> <low>
|
||||
placement everyone|admins|nobody clear-objects
|
||||
objects <number>|off How many objects each player may have placed.
|
||||
object-scaling on|off Whether players may resize the objects they place.
|
||||
noclip on|off nobail on|off boosts on|off
|
||||
What players may use (admins always can).
|
||||
tuning on|off Everyone on the game's own physics tuning.
|
||||
|
||||
@@ -192,6 +192,17 @@ int run() {
|
||||
"A config in sections did not read back as it was written");
|
||||
std::filesystem::remove_all(folder / "data");
|
||||
}
|
||||
// Object scaling: allowed unless turned off, and kept in the file.
|
||||
{
|
||||
ServerConfig sized;
|
||||
check(sized.object_scaling, "Object scaling is not allowed by default");
|
||||
sized.file = folder / "sized.json";
|
||||
sized.object_scaling = false;
|
||||
save_config(sized);
|
||||
check(!load_config(sized.file).object_scaling && text(sized.file).find("\"allow_object_scaling\": false") != std::string::npos,
|
||||
"The object scaling setting was not kept");
|
||||
std::filesystem::remove_all(folder / "data");
|
||||
}
|
||||
// The server's chat colours: violet and lavender unless set, red first as written.
|
||||
{
|
||||
ServerConfig colours;
|
||||
|
||||
@@ -16,7 +16,7 @@ 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"
|
||||
"map <name, e.g. San Vansterdam> | maps | 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\n"
|
||||
"placement everyone|admins|nobody | objects <number>|off | clear-objects | noclip on|off | nobail on|off | boosts on|off | tuning on|off\n"
|
||||
"placement everyone|admins|nobody | objects <number>|off | object-scaling on|off | clear-objects | noclip on|off | nobail on|off | boosts on|off | tuning on|off\n"
|
||||
"tpall [player] | tphere <player> | votes [map|kick|tod on|off|<percent>] | vote-cancel\n"
|
||||
"map-pool [add|remove <map>|clear] | rotation [<minutes>|off]\n"
|
||||
"park <lot> <layout> | park random | layer-sync on|off | layer <key> default|on|off | tod <time|default>\n"
|
||||
@@ -438,6 +438,14 @@ std::string Host::command(std::string_view line, std::uint64_t admin) {
|
||||
return changed(*limit ? "Each player can place up to " + std::to_string(*limit) + " objects. Admins are not limited."
|
||||
: std::string("Players can place as many objects as they like."));
|
||||
}
|
||||
if (name == "object-scaling") {
|
||||
const auto value = on_off(argument);
|
||||
if (!value) return std::string("object-scaling on|off (now ") + (config_.object_scaling ? "on" : "off") + ")";
|
||||
config_.object_scaling = *value;
|
||||
for (auto &[id, guest] : guests_) guest->shared_from = 0; // look at every layout again
|
||||
return changed(*value ? "Players can resize the objects they place."
|
||||
: "Placed objects are their own size for everyone. Admins can still resize theirs.");
|
||||
}
|
||||
if (name == "votes") {
|
||||
// votes | votes <map|kick|tod> on|off|<percent> | votes seconds|cooldown <n>
|
||||
const auto [what_text, value_text] = split(argument);
|
||||
|
||||
@@ -103,6 +103,7 @@ Layout layout(const ServerConfig &c) {
|
||||
players.set("voice_range", static_cast<double>(c.voice_range));
|
||||
players.set("object_placement", placement_text(c.object_placement));
|
||||
players.set("object_limit", c.object_limit);
|
||||
players.set("allow_object_scaling", c.object_scaling);
|
||||
players.set("announce_throwdowns", c.announce_throwdowns);
|
||||
|
||||
auto &anti_cheat = root.section("anti_cheat");
|
||||
@@ -256,6 +257,7 @@ ServerConfig load_config(const std::filesystem::path &file, std::vector<std::str
|
||||
c.object_placement = placement == "nobody" ? ObjectPlacement::nobody
|
||||
: placement == "admins" || placement == "host" ? ObjectPlacement::host_only : ObjectPlacement::everyone;
|
||||
c.object_limit = get("players", "object_limit", c.object_limit);
|
||||
c.object_scaling = get("players", "allow_object_scaling", c.object_scaling);
|
||||
c.announce_throwdowns = get("players", "announce_throwdowns", c.announce_throwdowns);
|
||||
|
||||
c.speed_check = get("anti_cheat", "speed_hack", c.speed_check, {"speed_check"});
|
||||
|
||||
@@ -100,6 +100,9 @@ struct ServerConfig {
|
||||
ObjectPlacement object_placement = ObjectPlacement::everyone;
|
||||
// Objects each player may have placed (object_placement.h); 0: no limit. Admins are not held to it.
|
||||
unsigned object_limit = default_object_limit;
|
||||
// Players may place objects at another size than their own. Off: every player's objects
|
||||
// are shared at their own size; admins may still resize theirs.
|
||||
bool object_scaling = true;
|
||||
// Whether players may use noclip (and teleport) / No Bail / the boosts (admins always may).
|
||||
bool noclip = true, no_bail = true, boosts = true;
|
||||
// Players skate with the game's own physics tuning, not copies they edited.
|
||||
|
||||
@@ -576,6 +576,7 @@ void Host::send_roster() {
|
||||
p.distances = config_.distances;
|
||||
p.object_placement = config_.object_placement;
|
||||
p.object_limit = config_.object_limit;
|
||||
p.object_scaling = config_.object_scaling;
|
||||
p.guest_noclip = config_.noclip;
|
||||
p.guest_no_bail = config_.no_bail;
|
||||
p.guest_boosts = config_.boosts;
|
||||
@@ -1113,6 +1114,10 @@ void Host::sync_objects() {
|
||||
std::erase_if(layout, [&](const auto &object) { return guest->cleared.contains(object.id); });
|
||||
// No more of a player's objects than the server allows each of them; admins are not limited.
|
||||
if (!is_admin(id)) layout = limited_layout(std::move(layout), guest->shared.objects(), config_.object_limit);
|
||||
// With scaling off, a player's objects reach everyone else at their own size, whatever
|
||||
// that player's game made of them.
|
||||
if (!config_.object_scaling && !is_admin(id))
|
||||
for (auto &object : layout) object.scale = 1.f;
|
||||
if (config_.activity_log) activity_.objects(id, guest->shared.layout(), layout);
|
||||
guest->shared.replace(layout);
|
||||
guest->shared_from = guest->objects.revision();
|
||||
|
||||
+1559
-1604
File diff suppressed because it is too large.
Load diff
Binary file not shown.
|
Before Width: | Height: | Size: 2.0 MiB After Width: | Height: | Size: 2.1 MiB |
Reference in new issue
Block a user