2.10.11: security levels (no joining servers/hosts below the required level, OUTDATED in the browser), announcements and maintenance notice from the keymaster in the MSCO menu

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-23 20:26:52 +02:00
co-authored by Claude Opus 5.5
parent ceaa2e29aa
commit 8bac7d194a
6 changed files with 263 additions and 4 deletions
+54 -3
View File
@@ -72,7 +72,12 @@ namespace MSCO
string layoutError;
GUIStyle dangerStyle;
GUIStyle windowBox, sidebarBox, rowBox, accentBox, pillStyle, pillMutedStyle, chipOnStyle, chipOffStyle;
GUIStyle featuredRowBox, pillFeaturedStyle;
GUIStyle featuredRowBox, pillFeaturedStyle, pillDangerStyle, newsTitleStyle;
// Ankündigungen/Wartung vom Keymaster - nur im Layout-Durchgang übernehmen (Liste kann sich im Hintergrund ändern)
List<Announcement> shownNews;
bool shownMaintenance;
string shownMaintenanceText;
readonly HashSet<string> dismissedNews = new HashSet<string>();
GUIStyle betaPillStyle, betaNoteStyle;
GUIStyle logoStyle, taglineStyle, navStyle, navActiveStyle, titleStyle, textStyle, captionStyle,
fieldStyle, primaryStyle, secondaryStyle, statusStyle, tabStyle, headerCellStyle,
@@ -141,6 +146,7 @@ namespace MSCO
GUI.skin.verticalScrollbar = scrollbarStyle;
GUI.skin.verticalScrollbarThumb = scrollThumbStyle;
GUILayout.BeginArea(content);
if (!versionWarning && !pendingJoin && !mp.IsInSession) DrawAnnouncements();
if (versionWarning) DrawVersionWarning(mp);
else if (pendingJoin) DrawJoinConfirm(mp);
else if (mp.IsInSession) DrawSession(mp);
@@ -358,6 +364,7 @@ namespace MSCO
// Server auf diesem PC (localhost)
nameX += Pill(nameX, row, "LOCAL", pillStyle);
}
if (s.Outdated) nameX += Pill(nameX, row, "OUTDATED", pillDangerStyle); // fehlende Sicherheitsupdates
if (!string.IsNullOrEmpty(s.Version) && !MSCO.Compatible(s.Version))
{
nameX += Pill(nameX, row, "v" + s.Version, pillStyle); // abweichende Version
@@ -408,7 +415,43 @@ namespace MSCO
static bool CanJoin(MultiplayerManager mp, ServerListEntry s)
{
return s.Players < s.MaxPlayers && (!s.RequireSteam || mp.SteamAvailable);
return !s.Outdated && s.Players < s.MaxPlayers && (!s.RequireSteam || mp.SteamAvailable);
}
/// <summary>
/// Oben im MSCO-Menü: Wartungshinweis und Ankündigungen der MSCO-Admins (Keymaster → Wartung &amp; News).
/// Ankündigungen lassen sich mit × für diese Sitzung ausblenden.
/// </summary>
void DrawAnnouncements()
{
if (shownNews == null || Event.current.type == EventType.Layout)
{
shownNews = SiteStatus.Announcements.FindAll(a => !dismissedNews.Contains(a.Id));
if (shownNews.Count > 3) shownNews.RemoveRange(3, shownNews.Count - 3);
shownMaintenance = SiteStatus.Maintenance;
shownMaintenanceText = SiteStatus.MaintenanceMessage;
}
if (shownMaintenance)
NewsBox("MAINTENANCE", pillFeaturedStyle, "MSCO is in maintenance right now",
string.IsNullOrEmpty(shownMaintenanceText) ? "Some things may not work for a while." : shownMaintenanceText, null);
foreach (Announcement a in shownNews)
NewsBox(a.Level == "critical" ? "IMPORTANT" : a.Level == "warning" ? "NOTICE" : "INFO",
a.Level == "critical" ? pillDangerStyle : a.Level == "warning" ? pillFeaturedStyle : pillMutedStyle, a.Title, a.Text, a.Id);
if (shownMaintenance || shownNews.Count > 0) GUILayout.Space(S(10));
}
void NewsBox(string label, GUIStyle pill, string title, string text, string id)
{
GUILayout.BeginVertical(rowBox);
GUILayout.BeginHorizontal();
GUILayout.Label(label, pill, GUILayout.Height(S(20)), GUILayout.ExpandWidth(false));
GUILayout.Space(S(8));
GUILayout.Label(title, newsTitleStyle, GUILayout.ExpandWidth(true));
if (id != null && GUILayout.Button("×", tabStyle, GUILayout.Width(S(28)), GUILayout.Height(S(22)))) dismissedNews.Add(id);
GUILayout.EndHorizontal();
if (!string.IsNullOrEmpty(text)) GUILayout.Label(text, textStyle);
GUILayout.EndVertical();
GUILayout.Space(S(6));
}
void DrawNameField(MultiplayerManager mp, float width)
@@ -613,6 +656,7 @@ namespace MSCO
if (official) bx += Pill(bx, badgeRow, "OFFICIAL", pillStyle);
bx += Pill(bx, badgeRow, s.RequireSteam ? "STEAM" : "NON-STEAM", s.RequireSteam ? pillStyle : pillMutedStyle);
if (s.IsLocal) bx += Pill(bx, badgeRow, "LOCAL", pillStyle);
if (s.Outdated) bx += Pill(bx, badgeRow, "OUTDATED", pillDangerStyle);
if (!MSCO.Compatible(s.Version)) bx += Pill(bx, badgeRow, "v" + s.Version, pillStyle);
if (s.Tags != null)
foreach (string tag in s.Tags)
@@ -625,10 +669,13 @@ namespace MSCO
Heart(new Rect(heartSlot.x + S(11), heartSlot.y + S(11), S(22), S(22)), s);
GUILayout.Space(S(8));
GUI.enabled = CanJoin(mp, s);
if (GUILayout.Button(s.Players >= s.MaxPlayers ? "SERVER FULL" : "JOIN SERVER", primaryStyle, GUILayout.Height(S(44)), GUILayout.Width(S(180))))
if (GUILayout.Button(s.Outdated ? "UPDATE REQUIRED" : s.Players >= s.MaxPlayers ? "SERVER FULL" : "JOIN SERVER", primaryStyle, GUILayout.Height(S(44)), GUILayout.Width(S(180))))
mp.JoinServer(s.Address, s.Port, s.Name, s.MaxPlayers);
GUI.enabled = true;
GUILayout.EndHorizontal();
if (s.Outdated)
GUILayout.Label("This server is missing MSCO security updates" + (string.IsNullOrEmpty(s.ServerVersion) ? "" : " (server " + s.ServerVersion + ")") +
" - you can join again once its owner has updated it.", textStyle);
if (!string.IsNullOrEmpty(s.Description)) GUILayout.Label(s.Description, textStyle);
GUILayout.Space(S(10));
@@ -1118,6 +1165,10 @@ namespace MSCO
pillFeaturedStyle = new GUIStyle(pillStyle);
pillFeaturedStyle.normal.background = UiTheme.Rounded(Gold, P(4));
pillFeaturedStyle.normal.textColor = Hex(0x1a, 0x12, 0x06);
pillDangerStyle = new GUIStyle(pillStyle);
pillDangerStyle.normal.background = UiTheme.Rounded(new Color(UiTheme.Danger.r, UiTheme.Danger.g, UiTheme.Danger.b, 0.25f), P(4));
pillDangerStyle.normal.textColor = UiTheme.DangerHover;
newsTitleStyle = new GUIStyle(rowNameStyle) { wordWrap = true };
featuredRowBox = UiTheme.Card(Color.Lerp(Field, Gold, 0.14f), P(10));
chipOnStyle = Button(new Color(Accent.r, Accent.g, Accent.b, 0.2f), new Color(Accent.r, Accent.g, Accent.b, 0.3f), AccentHover, P(11), FontStyle.Bold, P(11), new Color(Accent.r, Accent.g, Accent.b, 0.55f));