Merge pull request #302 from wilu222/server-browser-sort-direction

Server browser: clicking the active column reverses its sort
This commit is contained in:
zeex64 authored and GitHub committed 2026-10-20 14:16:26 -05:00
commit ca3a20b5e6
3 files changed
+37 -9

No files matched your search

@@ -42,6 +42,10 @@ void map_names() {
result = browse(model, options, levels);
check(result.lobbies[0]->id == 2 && result.lobbies[1]->id == 1 && result.lobbies[2]->id == 3,
"Map sorting follows visible names instead of asset paths");
options.reverse = true;
result = browse(model, options, levels);
check(result.lobbies[0]->id == 3 && result.lobbies[1]->id == 1 && result.lobbies[2]->id == 2,
"Reversed map sorting follows visible names the other way");
}
int main() {
try {
@@ -71,6 +75,11 @@ int main() {
check(result.total == 14 && result.lobbies.size() == 14, "All matching lobbies remain scrollable");
check(result.lobbies.front()->id == 100 && result.lobbies[6]->id == 112 && result.lobbies.back()->id == 113,
"Stable ordering of duplicate names across the full list");
auto by_name_reversed = by_name;
by_name_reversed.reverse = true;
result = browse(model, by_name_reversed);
check(result.lobbies.front()->id == 101 && result.lobbies.back()->id == 112,
"Reversed names put Downtown first and keep equal names in id order");
BrowserOptions options;
options.query = "SAN VAN";
result = browse(model, options);
@@ -79,6 +88,10 @@ int main() {
check(browse(model, options).total == 5, "Combine name and current-map filters");
options = {}; options.sort = Sort::players;
check(browse(model, options).lobbies.front()->players == 14, "Most populated first");
options.reverse = true;
check(browse(model, options).lobbies.front()->id == 100 && browse(model, options).lobbies.front()->players == 1,
"Fewest skaters first when the column is reversed");
options.reverse = false;
// The team's own servers lead the list under every sort, in that sort's order among themselves.
model.lobbies[2].dedicated = model.lobbies[2].official = true;
model.lobbies[5].dedicated = model.lobbies[5].official = true;
+9 -5
View File
@@ -8,8 +8,9 @@
namespace dingosdk::multiplayer::menu_view {
enum class Sort { name, players, map };
// The busiest servers first, until the player picks another order.
struct BrowserOptions { std::string query; bool same_map{}; Sort sort = Sort::players; };
// The busiest servers first, until the player picks another order. A second click on that
// column sets reverse, which flips only that column.
struct BrowserOptions { std::string query; bool same_map{}; Sort sort = Sort::players; bool reverse{}; };
// Owned pages: Multiplayer and Mod Options (needs the overlay's tool callbacks).
inline constexpr unsigned page_count = 2, tools_page = 1;
@@ -79,13 +80,16 @@ inline BrowserResults browse(const MultiplayerModel& model, const BrowserOptions
if (a->official != b->official) return a->official;
// Then where friends are.
if (a->friends.empty() != b->friends.empty()) return !a->friends.empty();
if (options.sort == Sort::players && a->players != b->players) return a->players > b->players;
if (options.sort == Sort::players && a->players != b->players)
return options.reverse ? a->players < b->players : a->players > b->players;
if (options.sort == Sort::map) {
const auto an = fold(map_name(a->map, levels)), bn = fold(map_name(b->map, levels));
if (an != bn) return an < bn;
if (an != bn) return options.reverse ? an > bn : an < bn;
}
const auto an = fold(a->name), bn = fold(b->name);
return an != bn ? an < bn : a->id < b->id;
// A name or map tie stays A to Z, then by id. Reversing NAME flips the names themselves.
if (an != bn) return options.sort == Sort::name && options.reverse ? an > bn : an < bn;
return a->id < b->id;
});
result.total = result.lobbies.size();
return result;
+15 -4
View File
@@ -127,6 +127,7 @@ struct Hub {
std::set<std::uint64_t> favorites;
bool favorites_loaded{}, favorites_only{};
view::Sort sort{view::Sort::players};
bool sort_reverse{}; // a second click on the active column
std::uint64_t selected{};
// Hosting.
std::string host_name, host_password;
@@ -395,7 +396,7 @@ void rebuild(Hub &h) {
h.rows.clear();
const auto &mp = h.model;
const std::span<const Level> levels = h.full.levels;
const auto found = view::browse(mp, {h.search, h.same_map, h.sort}, levels);
const auto found = view::browse(mp, {h.search, h.same_map, h.sort, h.sort_reverse}, levels);
h.listed = mp.lobbies.size();
h.skaters = 0;
for (const auto &lobby : mp.lobbies) h.skaters += std::max(0, lobby.players);
@@ -472,7 +473,8 @@ void browser_page(Ui &ui, ImVec2 a, ImVec2 z) {
queue_multiplayer_action("browse", "");
}
if (ui.input && !h.typing && (ui.pad.buttons & ~h.pad_before & 0x4000) && !wait) queue_multiplayer_action("browse", ""); // X / Square
if (ui.input && !h.typing && (ui.pad.buttons & ~h.pad_before & 0x8000)) h.sort = static_cast<view::Sort>((static_cast<int>(h.sort) + 1) % 3), changed = true; // Y / Triangle
if (ui.input && !h.typing && (ui.pad.buttons & ~h.pad_before & 0x8000))
h.sort = static_cast<view::Sort>((static_cast<int>(h.sort) + 1) % 3), h.sort_reverse = false, changed = true; // Y / Triangle
// F marks the chosen server as a favorite, or takes the mark away.
if (ui.input && !h.typing && !h.code_mode && ImGui::IsKeyPressed(ImGuiKey_F, false))
if (const auto *row = selected_row(h); row && row->lobby->dedicated) toggle_favorite(h, *row->lobby), changed = true;
@@ -489,8 +491,17 @@ void browser_page(Ui &ui, ImVec2 a, ImVec2 z) {
const bool on = h.sort == sort;
const Hit hit = item(ui, hash(text, 9), c, d);
draw->AddText(ui.bold, size, ImVec2(c.x, c.y + 8 * u), on || hit.focus || hit.hover ? theme::blue : theme::muted, text);
if (on) draw->AddTriangleFilled(ImVec2(c.x + w + 10 * u, c.y + 16 * u), ImVec2(c.x + w + 26 * u, c.y + 16 * u), ImVec2(c.x + w + 18 * u, c.y + 28 * u), theme::blue);
if (hit.press && !on) h.sort = sort, changed = true;
if (on) {
// Down is most-skaters-first, or Z to A. Up is the other way.
const bool down = (sort == view::Sort::players) != h.sort_reverse;
const float y0 = c.y + (down ? 16 * u : 28 * u), y1 = c.y + (down ? 28 * u : 16 * u);
draw->AddTriangleFilled(ImVec2(c.x + w + 10 * u, y0), ImVec2(c.x + w + 26 * u, y0), ImVec2(c.x + w + 18 * u, y1), theme::blue);
}
if (hit.press) {
if (on) h.sort_reverse = !h.sort_reverse;
else h.sort = sort, h.sort_reverse = false;
changed = true;
}
};
column("NAME", la.x + pad_x, view::Sort::name, false);
column("MAP", map_x, view::Sort::map, false);