Server browser: featured servers (gold row + FEATURED badge, pinned to the top by the master) and key tags in the server profile; search matches tags

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Nico Meister
2026-09-27 23:55:46 +02:00
co-authored by Claude Opus 5.5
parent 8e00640732
commit 33a415139b
3 changed files with 26 additions and 3 deletions
+8
View File
@@ -1,5 +1,13 @@
# Changelog # Changelog
## Nächste Version
**Server-Browser**
- **Hervorgehobene Server**: vom Keymaster-Admin markierte Server (Tag `featured`) stehen ganz oben, mit goldener
Zeile und **FEATURED**-Abzeichen (Liste und Profil)
- **Tags** der Server (z.B. `OFFICIAL`) erscheinen im Server-Profil; die Suche findet auch Tags
- Braucht keinen neuen Server: die Infos kommen vom Master (msco.mbm.wtf) und funktionieren mit 2.8-Servern
## 2.8 ## 2.8
Server und Mod müssen beide 2.8 sein (Server: `git pull && docker compose up -d --build`). Server und Mod müssen beide 2.8 sein (Server: `git pull && docker compose up -d --build`).
+16 -3
View File
@@ -29,6 +29,7 @@ namespace MSCO
static readonly Color Muted = Hex(0x8e, 0x8e, 0x99); static readonly Color Muted = Hex(0x8e, 0x8e, 0x99);
static readonly Color Online = Hex(0x3d, 0xd6, 0x8c); static readonly Color Online = Hex(0x3d, 0xd6, 0x8c);
static readonly Color Pending = Hex(0xf2, 0xc2, 0x1d); static readonly Color Pending = Hex(0xf2, 0xc2, 0x1d);
static readonly Color Gold = Hex(0xff, 0xb4, 0x5a); // hervorgehobene (featured) Server
Page page = Page.P2P; Page page = Page.P2P;
Vector2 profileScroll; Vector2 profileScroll;
@@ -54,6 +55,7 @@ namespace MSCO
string layoutError; string layoutError;
GUIStyle dangerStyle; GUIStyle dangerStyle;
GUIStyle windowBox, sidebarBox, rowBox, accentBox, pillStyle, pillMutedStyle, chipOnStyle, chipOffStyle; GUIStyle windowBox, sidebarBox, rowBox, accentBox, pillStyle, pillMutedStyle, chipOnStyle, chipOffStyle;
GUIStyle featuredRowBox, pillFeaturedStyle;
GUIStyle logoStyle, taglineStyle, navStyle, navActiveStyle, titleStyle, textStyle, captionStyle, GUIStyle logoStyle, taglineStyle, navStyle, navActiveStyle, titleStyle, textStyle, captionStyle,
fieldStyle, primaryStyle, secondaryStyle, statusStyle, tabStyle, headerCellStyle, fieldStyle, primaryStyle, secondaryStyle, statusStyle, tabStyle, headerCellStyle,
rowNameStyle, rowTagStyle, badgeStyle, toggleStyle, placeholderStyle; rowNameStyle, rowTagStyle, badgeStyle, toggleStyle, placeholderStyle;
@@ -219,7 +221,8 @@ namespace MSCO
shownServers = all.FindAll(s => shownServers = all.FindAll(s =>
(s.RequireSteam ? showSteam : showNonSteam) && (s.RequireSteam ? showSteam : showNonSteam) &&
(!hideFull || s.Players < s.MaxPlayers) && (!hideFull || s.Players < s.MaxPlayers) &&
(search.Length == 0 || (s.Name ?? "").ToLower().Contains(search) || (s.Owner ?? "").ToLower().Contains(search))); (search.Length == 0 || (s.Name ?? "").ToLower().Contains(search) || (s.Owner ?? "").ToLower().Contains(search) ||
(s.Tags != null && s.Tags.Exists(t => (t ?? "").Contains(search)))));
List<ServerListEntry> servers = shownServers; List<ServerListEntry> servers = shownServers;
string shownError = Event.current.type == EventType.Layout ? (layoutError = browser.Error) : layoutError; string shownError = Event.current.type == EventType.Layout ? (layoutError = browser.Error) : layoutError;
@@ -238,7 +241,8 @@ namespace MSCO
foreach (ServerListEntry s in servers) foreach (ServerListEntry s in servers)
{ {
Rect row = GUILayoutUtility.GetRect(10, 34, GUILayout.ExpandWidth(true)); Rect row = GUILayoutUtility.GetRect(10, 34, GUILayout.ExpandWidth(true));
GUI.Box(new Rect(row.x, row.y + 2, row.width, row.height - 4), GUIContent.none, rowBox); // Hervorgehobene Server (Keymaster-Admin) stehen oben - der Master liefert sie zuerst
GUI.Box(new Rect(row.x, row.y + 2, row.width, row.height - 4), GUIContent.none, s.Featured ? featuredRowBox : rowBox);
// Herz: als Favorit merken / entfernen (vor dem Zeilen-Knopf, damit es den Klick bekommt) // Herz: als Favorit merken / entfernen (vor dem Zeilen-Knopf, damit es den Klick bekommt)
Heart(new Rect(row.xMax - 58, row.y + 7, 20, 20), s); Heart(new Rect(row.xMax - 58, row.y + 7, 20, 20), s);
@@ -250,6 +254,7 @@ namespace MSCO
GUI.DrawTexture(new Rect(row.x + 10, row.y + 13, 8, 8), s.Ping < 0 ? texPending : texOnline); GUI.DrawTexture(new Rect(row.x + 10, row.y + 13, 8, 8), s.Ping < 0 ? texPending : texOnline);
float nameX = row.x + 26; float nameX = row.x + 26;
Favorites.Favorite fav = Favorites.FindByAddress(s.Address, s.Port); Favorites.Favorite fav = Favorites.FindByAddress(s.Address, s.Port);
if (s.Featured) nameX += Pill(nameX, row, "FEATURED", pillFeaturedStyle);
if (fav != null) nameX += Pill(nameX, row, fav.Nickname, pillMutedStyle); if (fav != null) nameX += Pill(nameX, row, fav.Nickname, pillMutedStyle);
if (s.IsLocal) if (s.IsLocal)
{ {
@@ -501,9 +506,13 @@ namespace MSCO
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
Rect badgeRow = GUILayoutUtility.GetRect(10, 20, GUILayout.ExpandWidth(true)); Rect badgeRow = GUILayoutUtility.GetRect(10, 20, GUILayout.ExpandWidth(true));
float bx = badgeRow.x; float bx = badgeRow.x;
if (s.Featured) bx += Pill(bx, badgeRow, "FEATURED", pillFeaturedStyle);
bx += Pill(bx, badgeRow, s.RequireSteam ? "STEAM" : "NON-STEAM", s.RequireSteam ? pillStyle : pillMutedStyle); bx += Pill(bx, badgeRow, s.RequireSteam ? "STEAM" : "NON-STEAM", s.RequireSteam ? pillStyle : pillMutedStyle);
if (s.IsLocal) bx += Pill(bx, badgeRow, "LOCAL", pillStyle); if (s.IsLocal) bx += Pill(bx, badgeRow, "LOCAL", pillStyle);
if (s.Version != MSCO.ModVersion) Pill(bx, badgeRow, "v" + s.Version, pillStyle); if (s.Version != MSCO.ModVersion) bx += Pill(bx, badgeRow, "v" + s.Version, pillStyle);
if (s.Tags != null)
foreach (string tag in s.Tags)
if (!string.IsNullOrEmpty(tag) && tag != "featured") bx += Pill(bx, badgeRow, tag.ToUpper(), pillMutedStyle);
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.EndVertical(); GUILayout.EndVertical();
GUILayout.Space(12); GUILayout.Space(12);
@@ -815,6 +824,10 @@ namespace MSCO
pillMutedStyle = new GUIStyle(pillStyle); pillMutedStyle = new GUIStyle(pillStyle);
pillMutedStyle.normal.background = UiTheme.Rounded(new Color(1f, 1f, 1f, 0.08f), 4); pillMutedStyle.normal.background = UiTheme.Rounded(new Color(1f, 1f, 1f, 0.08f), 4);
pillMutedStyle.normal.textColor = Muted; pillMutedStyle.normal.textColor = Muted;
pillFeaturedStyle = new GUIStyle(pillStyle);
pillFeaturedStyle.normal.background = UiTheme.Rounded(Gold, 4);
pillFeaturedStyle.normal.textColor = Hex(0x1a, 0x12, 0x06);
featuredRowBox = UiTheme.Panel9(Color.Lerp(Field, Gold, 0.16f), UiTheme.Radius);
chipOnStyle = Button(new Color(Accent.r, Accent.g, Accent.b, 0.22f), new Color(Accent.r, Accent.g, Accent.b, 0.32f), AccentHover, 11, FontStyle.Bold); chipOnStyle = Button(new Color(Accent.r, Accent.g, Accent.b, 0.22f), new Color(Accent.r, Accent.g, Accent.b, 0.32f), AccentHover, 11, FontStyle.Bold);
chipOffStyle = Button(Field, FieldFocus, Muted, 11, FontStyle.Bold); chipOffStyle = Button(Field, FieldFocus, Muted, 11, FontStyle.Bold);
+2
View File
@@ -23,6 +23,8 @@ namespace MSCO
public string Version; public string Version;
public bool RequireSteam = true; // false = Non-Steam-Server public bool RequireSteam = true; // false = Non-Steam-Server
public string Owner; // Besitzer des Lizenzschlüssels public string Owner; // Besitzer des Lizenzschlüssels
public bool Featured; // vom Keymaster-Admin hervorgehoben (steht in der Liste oben)
public List<string> Tags = new List<string>(); // Tags des Lizenzschlüssels (Keymaster-Admin), z.B. "official"
[JsonIgnore] public int UptimeSeconds = -1; [JsonIgnore] public int UptimeSeconds = -1;
[JsonIgnore] public List<string> PlayerNames = new List<string>(); [JsonIgnore] public List<string> PlayerNames = new List<string>();