Favorites: heart toggle, Favorites tab with nicknames, /switch <nickname> quick server switch, fav command

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-27 18:24:00 +02:00
co-authored by Claude Opus 5.5
parent 8dae3ac13d
commit 8e00640732
6 changed files with 395 additions and 2 deletions
+6
View File
@@ -24,6 +24,12 @@ Server und Mod müssen beide 2.8 sein (Server: `git pull && docker compose up -d
- **Backups** mit Datum/Uhrzeit, **RESTORE** holt einen älteren Stand zurück (der aktuelle wird vorher gesichert) - **Backups** mit Datum/Uhrzeit, **RESTORE** holt einen älteren Stand zurück (der aktuelle wird vorher gesichert)
- Jede Aktion mit Sicherheitsabfrage; nur für Admins (vom Server geprüft) - Jede Aktion mit Sicherheitsabfrage; nur für Admins (vom Server geprüft)
**Favoriten**
- Herz neben jedem Server (Liste und Profil) merkt ihn als Favorit
- Neuer Tab **Favorites**: jedem Server einen eigenen Kurznamen geben, beitreten, entfernen, per Adresse hinzufügen
- Schnell wechseln: `/switch <kurzname>` im Chat oder `switch <kurzname>` in der F7-Konsole – trennt und verbindet
direkt mit dem anderen Server; `fav` listet alle, `fav add <name>` merkt den aktuellen Server
**Pro Spieler** **Pro Spieler**
- Hunger, Durst, Stress, Harndrang, Müdigkeit und Schmutz werden für jeden Spieler einzeln auf dem Server gespeichert - Hunger, Durst, Stress, Harndrang, Müdigkeit und Schmutz werden für jeden Spieler einzeln auf dem Server gespeichert
und beim Beitreten zurückgegeben (nicht mehr die Werte aus dem gemeinsamen Spielstand) und beim Beitreten zurückgegeben (nicht mehr die Werte aus dem gemeinsamen Spielstand)
+44
View File
@@ -10,6 +10,10 @@ namespace MSCO
{ {
public const string Help = public const string Help =
"connect <host[:port]> - join a dedicated server\n" + "connect <host[:port]> - join a dedicated server\n" +
"switch <nickname> - quickly switch to a favorite server (also /switch in chat)\n" +
"fav - list your favorite servers\n" +
"fav add <nick> [host:port] - add a favorite (without address: the server you are on)\n" +
"fav remove <nick> - remove a favorite\n" +
"disconnect - leave the server / game\n" + "disconnect - leave the server / game\n" +
"host [port] / join <ip> [port] - direct LAN game (no Steam)\n" + "host [port] / join <ip> [port] - direct LAN game (no Steam)\n" +
"save - save the game (host / singleplayer)\n" + "save - save the game (host / singleplayer)\n" +
@@ -19,6 +23,37 @@ namespace MSCO
"debug - toggle sync debug output\n" + "debug - toggle sync debug output\n" +
"clear - clear this console"; "clear - clear this console";
static void Favorite(MultiplayerManager mp, string[] args, Action<string> print)
{
string sub = args.Length > 1 ? args[1].ToLower() : "list";
if (sub == "list")
{
if (Favorites.All.Count == 0) { print("No favorites yet - open a server in the browser and press FAVORITE, or: fav add <nick>"); return; }
foreach (Favorites.Favorite f in Favorites.All)
print(" " + f.Nickname + " -> " + f.Address + (string.IsNullOrEmpty(f.ServerName) ? "" : " (" + f.ServerName + ")"));
print("switch <nickname> to join one");
return;
}
if (sub == "add" || sub == "set")
{
if (args.Length < 3) { print("fav add <nickname> [host:port]"); return; }
string host = mp.CurrentServerHost, name = mp.CurrentServerName;
int port = mp.CurrentServerPort;
if (args.Length > 3 && !ServerBrowser.TryParseAddress(args[3], out host, out port)) { print("Invalid address: " + args[3]); return; }
if (host == null) { print("You are not on a server - use: fav add <nickname> <host:port>"); return; }
string error = Favorites.Set(args[2], host, port, name);
print(error ?? "Favorite '" + Favorites.CleanNickname(args[2]) + "' saved (" + host + ":" + port + ")");
return;
}
if (sub == "remove" || sub == "del" || sub == "delete")
{
Favorites.Favorite f = args.Length > 2 ? Favorites.Find(args[2]) : null;
print(f != null && Favorites.Remove(f) ? "Favorite '" + f.Nickname + "' removed" : "No such favorite");
return;
}
print("fav | fav add <nick> [host:port] | fav remove <nick>");
}
public static void Execute(string[] args, Action<string> print) public static void Execute(string[] args, Action<string> print)
{ {
var mp = MultiplayerManager.Instance; var mp = MultiplayerManager.Instance;
@@ -59,6 +94,15 @@ namespace MSCO
mp.JoinServer(host, serverPort); mp.JoinServer(host, serverPort);
break; break;
} }
case "switch":
case "sw":
print(mp.SwitchServer(args.Length > 1 ? args[1] : ""));
break;
case "fav":
case "favs":
case "favorites":
Favorite(mp, args, print);
break;
case "save": case "save":
mp.SaveGame(); mp.SaveGame();
break; break;
+114
View File
@@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
namespace MSCO
{
/// <summary>
/// Lieblings-Server mit eigenem Kurznamen (z.B. "mbm"). Gespeichert in den PlayerPrefs, eine Zeile pro Server:
/// Kurzname, Adresse, Port, Servername (Tab-getrennt). Mit "switch <kurzname>" wechselt man schnell den Server.
/// </summary>
public static class Favorites
{
public class Favorite
{
public string Nickname;
public string Host;
public int Port;
public string ServerName;
public string Address { get { return Host + ":" + Port; } }
}
const string Pref = "MSCO_Favorites";
const int MaxFavorites = 30;
static List<Favorite> list;
public static List<Favorite> All { get { Load(); return list; } }
static void Load()
{
if (list != null) return;
list = new List<Favorite>();
string raw = PlayerPrefs.GetString(Pref, "");
foreach (string line in raw.Split('\n'))
{
string[] p = line.Split('\t');
int port;
if (p.Length < 3 || p[0].Length == 0 || p[1].Length == 0 || !int.TryParse(p[2], out port)) continue;
list.Add(new Favorite { Nickname = p[0], Host = p[1], Port = port, ServerName = p.Length > 3 ? p[3] : "" });
}
}
static void Save()
{
var sb = new StringBuilder();
foreach (Favorite f in list)
sb.Append(Clean(f.Nickname)).Append('\t').Append(Clean(f.Host)).Append('\t').Append(f.Port).Append('\t').Append(Clean(f.ServerName)).Append('\n');
PlayerPrefs.SetString(Pref, sb.ToString());
PlayerPrefs.Save();
}
static string Clean(string s) { return (s ?? "").Replace("\t", " ").Replace("\n", " ").Trim(); }
/// <summary>Kurzname: Buchstaben, Zahlen, - und _ (ohne Leerzeichen, damit "switch name" eindeutig ist).</summary>
public static string CleanNickname(string nickname)
{
var sb = new StringBuilder();
foreach (char c in (nickname ?? "").Trim())
if (char.IsLetterOrDigit(c) || c == '-' || c == '_') sb.Append(c);
string s = sb.ToString();
return s.Length > 20 ? s.Substring(0, 20) : s;
}
public static Favorite Find(string nickname)
{
Load();
return list.Find(f => string.Equals(f.Nickname, nickname, StringComparison.OrdinalIgnoreCase));
}
public static Favorite FindByAddress(string host, int port)
{
Load();
return list.Find(f => f.Port == port && string.Equals(f.Host, host, StringComparison.OrdinalIgnoreCase));
}
/// <summary>Hinzufügen oder (gleiche Adresse) umbenennen. Gibt einen Fehler zurück oder null.</summary>
public static string Set(string nickname, string host, int port, string serverName)
{
Load();
nickname = CleanNickname(nickname);
if (nickname.Length == 0) return "Nickname: letters, numbers, - and _";
if (string.IsNullOrEmpty(host) || port <= 0 || port > 65535) return "Invalid server address";
Favorite sameName = Find(nickname);
Favorite existing = FindByAddress(host, port);
if (sameName != null && sameName != existing) return "The nickname '" + nickname + "' is already used for " + sameName.Address;
if (existing == null)
{
if (list.Count >= MaxFavorites) return "Too many favorites (max " + MaxFavorites + ")";
existing = new Favorite { Host = host, Port = port };
list.Add(existing);
}
existing.Nickname = nickname;
if (!string.IsNullOrEmpty(serverName)) existing.ServerName = serverName;
Save();
return null;
}
public static bool Remove(Favorite f)
{
Load();
if (f == null || !list.Remove(f)) return false;
Save();
return true;
}
/// <summary>Vorschlag für den Kurznamen aus dem Servernamen (erstes Wort, klein).</summary>
public static string SuggestNickname(string serverName)
{
string first = (serverName ?? "").Trim().Split(' ')[0];
string nick = CleanNickname(first).ToLower();
return nick.Length > 0 ? nick : "server";
}
}
}
+183 -2
View File
@@ -10,7 +10,7 @@ namespace MSCO
/// </summary> /// </summary>
public class LobbyUI public class LobbyUI
{ {
enum Page { P2P, ServerBrowser } enum Page { P2P, ServerBrowser, Favorites }
const float Width = 760f; const float Width = 760f;
const float Height = 460f; const float Height = 460f;
@@ -40,6 +40,10 @@ namespace MSCO
string selectedServer; // "adresse:port" des geöffneten Server-Profils string selectedServer; // "adresse:port" des geöffneten Server-Profils
string searchInput = ""; string searchInput = "";
bool showSteam = true, showNonSteam = true, hideFull; bool showSteam = true, showNonSteam = true, hideFull;
readonly Dictionary<string, string> nicknameEdits = new Dictionary<string, string>(); // Favoriten-Tab: Adresse -> bearbeiteter Kurzname
string favoriteAddInput = "";
Vector2 favoritesScroll;
Texture2D texHeartOn, texHeartOff;
string nameInput; string nameInput;
string directInput; string directInput;
const string PrefDirect = "MSCO_LastServer"; const string PrefDirect = "MSCO_LastServer";
@@ -92,6 +96,7 @@ namespace MSCO
else if (pendingJoin) DrawJoinConfirm(mp); else if (pendingJoin) DrawJoinConfirm(mp);
else if (mp.IsInSession) DrawSession(mp); else if (mp.IsInSession) DrawSession(mp);
else if (page == Page.P2P) DrawP2P(mp); else if (page == Page.P2P) DrawP2P(mp);
else if (page == Page.Favorites) DrawFavorites(mp);
else DrawServerBrowser(mp); else DrawServerBrowser(mp);
GUILayout.EndArea(); GUILayout.EndArea();
@@ -118,6 +123,9 @@ namespace MSCO
if (NavButton(new Rect(r.x, y, r.width, 42), "P2P", page == Page.P2P)) page = Page.P2P; if (NavButton(new Rect(r.x, y, r.width, 42), "P2P", page == Page.P2P)) page = Page.P2P;
y += 44; y += 44;
if (NavButton(new Rect(r.x, y, r.width, 42), "Server Browser", page == Page.ServerBrowser)) page = Page.ServerBrowser; if (NavButton(new Rect(r.x, y, r.width, 42), "Server Browser", page == Page.ServerBrowser)) page = Page.ServerBrowser;
y += 44;
int favCount = Favorites.All.Count;
if (NavButton(new Rect(r.x, y, r.width, 42), "Favorites" + (favCount > 0 ? " (" + favCount + ")" : ""), page == Page.Favorites)) page = Page.Favorites;
// Eigenes Hauptmenü: Spiel beenden (die Knöpfe des Spiel-Menüs sind ausgeblendet) // Eigenes Hauptmenü: Spiel beenden (die Knöpfe des Spiel-Menüs sind ausgeblendet)
if (quitConfirm) if (quitConfirm)
@@ -232,12 +240,17 @@ namespace MSCO
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); GUI.Box(new Rect(row.x, row.y + 2, row.width, row.height - 4), GUIContent.none, rowBox);
// 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);
// Klick auf die Zeile öffnet das Server-Profil (dort wird verbunden) // Klick auf die Zeile öffnet das Server-Profil (dort wird verbunden)
if (GUI.Button(new Rect(row.x, row.y, row.width, row.height), GUIContent.none, GUIStyle.none)) if (GUI.Button(new Rect(row.x, row.y, row.width, row.height), GUIContent.none, GUIStyle.none))
selectedServer = s.Address + ":" + s.Port; selectedServer = s.Address + ":" + s.Port;
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);
if (fav != null) nameX += Pill(nameX, row, fav.Nickname, pillMutedStyle);
if (s.IsLocal) if (s.IsLocal)
{ {
// Server auf diesem PC (localhost) // Server auf diesem PC (localhost)
@@ -302,6 +315,168 @@ namespace MSCO
} }
} }
// ---------------------------------------------------------------- Favoriten
/// <summary>Herz: gefüllt = Favorit. Klick merkt den Server (Kurzname aus dem Namen) bzw. entfernt ihn.</summary>
void Heart(Rect r, ServerListEntry s)
{
EnsureHearts();
Favorites.Favorite fav = Favorites.FindByAddress(s.Address, s.Port);
bool hover = r.Contains(Event.current.mousePosition);
GUI.DrawTexture(r, fav != null || hover ? texHeartOn : texHeartOff);
if (GUI.Button(r, GUIContent.none, GUIStyle.none))
{
if (fav != null) Favorites.Remove(fav);
else AddFavorite(s.Name, s.Address, s.Port);
}
}
static void AddFavorite(string serverName, string host, int port)
{
// Kurzname aus dem Servernamen; ist er schon vergeben, eine Zahl anhängen
string baseNick = Favorites.SuggestNickname(serverName), nick = baseNick;
for (int i = 2; Favorites.Find(nick) != null && i < 100; i++) nick = baseNick + i;
string error = Favorites.Set(nick, host, port, serverName);
if (error != null) MscoLog.Warning(error);
}
/// <summary>Tab "Favorites": Kurznamen setzen, beitreten, entfernen, per Adresse hinzufügen.</summary>
void DrawFavorites(MultiplayerManager mp)
{
EnsureHearts();
GUILayout.Label("Favorites", titleStyle);
GUILayout.Label("Give each server a nickname - switch in the game with /switch <nickname> in the chat or F7 console.", textStyle);
GUILayout.Space(8);
List<Favorites.Favorite> favs = Favorites.All;
favoritesScroll = GUILayout.BeginScrollView(favoritesScroll, GUILayout.Height(220));
if (favs.Count == 0)
GUILayout.Label("No favorites yet. Click the heart next to a server in the Server Browser, or add one by address below.", textStyle);
Favorites.Favorite remove = null;
foreach (Favorites.Favorite f in favs)
{
ServerListEntry live = mp.Browser.Servers.Find(x => x.Port == f.Port && string.Equals(x.Address, f.Host, System.StringComparison.OrdinalIgnoreCase));
GUILayout.BeginHorizontal(rowBox, GUILayout.Height(44));
GUILayout.Space(6);
// Herz (entfernen)
Rect heart = GUILayoutUtility.GetRect(22, 22, GUILayout.Width(22), GUILayout.Height(40));
Rect heartIcon = new Rect(heart.x, heart.y + 10, 20, 20);
GUI.DrawTexture(heartIcon, texHeartOn);
if (GUI.Button(heartIcon, GUIContent.none, GUIStyle.none)) remove = f;
GUILayout.Space(8);
// Kurzname bearbeiten
string edit;
if (!nicknameEdits.TryGetValue(f.Address, out edit)) edit = f.Nickname;
GUILayout.BeginVertical(GUILayout.Width(150));
GUILayout.Space(7);
edit = GUILayout.TextField(edit, 20, fieldStyle, GUILayout.Height(28), GUILayout.Width(150));
GUILayout.EndVertical();
nicknameEdits[f.Address] = edit;
GUILayout.Space(6);
bool changed = Favorites.CleanNickname(edit) != f.Nickname;
GUILayout.BeginVertical(GUILayout.Width(64));
GUILayout.Space(7);
GUI.enabled = changed;
if (GUILayout.Button("SAVE", tabStyle, GUILayout.Height(28), GUILayout.Width(64)))
{
string error = Favorites.Set(edit, f.Host, f.Port, f.ServerName);
if (error != null) MscoLog.Warning(error);
nicknameEdits.Remove(f.Address);
}
GUI.enabled = true;
GUILayout.EndVertical();
GUILayout.Space(10);
// Server + Status
GUILayout.BeginVertical();
GUILayout.Space(4);
GUILayout.Label(string.IsNullOrEmpty(f.ServerName) ? f.Address : f.ServerName, rowNameStyle);
GUILayout.Label(live == null ? f.Address + " · not listed / offline"
: f.Address + " · " + live.Players + "/" + live.MaxPlayers + " · " + (live.Ping < 0 ? "..." : live.Ping + " ms"), textStyle);
GUILayout.EndVertical();
GUILayout.FlexibleSpace();
GUILayout.BeginVertical(GUILayout.Width(90));
GUILayout.Space(7);
if (GUILayout.Button("JOIN", primaryStyle, GUILayout.Height(30), GUILayout.Width(90))) mp.SwitchServer(f.Nickname);
GUILayout.EndVertical();
GUILayout.Space(6);
GUILayout.EndHorizontal();
GUILayout.Space(4);
}
if (remove != null) { Favorites.Remove(remove); nicknameEdits.Remove(remove.Address); }
GUILayout.EndScrollView();
GUILayout.FlexibleSpace();
GUILayout.Label("ADD BY ADDRESS", captionStyle);
GUILayout.BeginHorizontal();
favoriteAddInput = GUILayout.TextField(favoriteAddInput ?? "", 60, fieldStyle, GUILayout.Height(34));
if (string.IsNullOrEmpty(favoriteAddInput))
{
Rect field = GUILayoutUtility.GetLastRect();
GUI.Label(new Rect(field.x + 10, field.y, field.width, field.height), "host:port", placeholderStyle);
}
GUILayout.Space(10);
if (GUILayout.Button("ADD", secondaryStyle, GUILayout.Height(34), GUILayout.Width(110)))
{
string host;
int port;
if (ServerBrowser.TryParseAddress(favoriteAddInput, out host, out port))
{
ServerListEntry live = mp.Browser.Servers.Find(x => x.Port == port && x.Address == host);
AddFavorite(live != null ? live.Name : host, host, port);
favoriteAddInput = "";
}
else MscoLog.Warning("Enter an address like 1.2.3.4:7777");
}
GUILayout.EndHorizontal();
}
void EnsureHearts()
{
if (texHeartOn != null && texHeartOff != null) return;
texHeartOn = HeartTexture(new Color(0.93f, 0.28f, 0.33f), true);
texHeartOff = HeartTexture(new Color(1f, 1f, 1f, 0.35f), false);
}
/// <summary>Herz als Textur (gefüllt oder nur Umriss), weich geglättet.</summary>
static Texture2D HeartTexture(Color color, bool filled)
{
const int size = 48;
var tex = new Texture2D(size, size, TextureFormat.ARGB32, false);
for (int py = 0; py < size; py++)
for (int px = 0; px < size; px++)
{
// Herz-Kurve (x² + y² - 1)³ - x² y³ <= 0, mehrfach abgetastet für glatte Kanten
int inside = 0, samples = 0;
for (int sy = 0; sy < 3; sy++)
for (int sx = 0; sx < 3; sx++)
{
float x = ((px + (sx + 0.5f) / 3f) / size - 0.5f) * 2.6f;
float y = ((py + (sy + 0.5f) / 3f) / size - 0.55f) * 2.6f;
float a = x * x + y * y - 1f;
bool inHeart = a * a * a - x * x * y * y * y <= 0f;
if (!filled && inHeart)
{
// Umriss: innen ein kleineres Herz aussparen
float x2 = x * 1.28f, y2 = (y + 0.08f) * 1.28f;
float b = x2 * x2 + y2 * y2 - 1f;
if (b * b * b - x2 * x2 * y2 * y2 * y2 <= 0f) inHeart = false;
}
if (inHeart) inside++;
samples++;
}
tex.SetPixel(px, py, new Color(color.r, color.g, color.b, color.a * inside / samples));
}
tex.filterMode = FilterMode.Bilinear;
tex.wrapMode = TextureWrapMode.Clamp;
tex.Apply();
tex.hideFlags = HideFlags.HideAndDontSave;
return tex;
}
/// <summary>Server-Profil: wem der Server gehört, Version, Spieler, Laufzeit ...</summary> /// <summary>Server-Profil: wem der Server gehört, Version, Spieler, Laufzeit ...</summary>
void DrawServerProfile(MultiplayerManager mp, ServerListEntry s) void DrawServerProfile(MultiplayerManager mp, ServerListEntry s)
{ {
@@ -332,6 +507,10 @@ namespace MSCO
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUILayout.EndVertical(); GUILayout.EndVertical();
GUILayout.Space(12); GUILayout.Space(12);
Rect heartSlot = GUILayoutUtility.GetRect(44, 44, GUILayout.Width(44), GUILayout.Height(44));
GUI.Box(heartSlot, GUIContent.none, rowBox);
Heart(new Rect(heartSlot.x + 11, heartSlot.y + 11, 22, 22), s);
GUILayout.Space(8);
GUI.enabled = CanJoin(mp, s); GUI.enabled = CanJoin(mp, s);
if (GUILayout.Button(s.Players >= s.MaxPlayers ? "SERVER FULL" : "JOIN SERVER", primaryStyle, GUILayout.Height(44), GUILayout.Width(180))) if (GUILayout.Button(s.Players >= s.MaxPlayers ? "SERVER FULL" : "JOIN SERVER", primaryStyle, GUILayout.Height(44), GUILayout.Width(180)))
mp.JoinServer(s.Address, s.Port, s.Name, s.MaxPlayers); mp.JoinServer(s.Address, s.Port, s.Name, s.MaxPlayers);
@@ -511,7 +690,9 @@ namespace MSCO
var r = new Rect((Screen.width - PromptWidth) / 2f, (Screen.height - PromptHeight) / 2f, PromptWidth, PromptHeight); var r = new Rect((Screen.width - PromptWidth) / 2f, (Screen.height - PromptHeight) / 2f, PromptWidth, PromptHeight);
ScreenRect = new Rect(0, 0, Screen.width, Screen.height); // Spielmenü dahinter komplett sperren ScreenRect = new Rect(0, 0, Screen.width, Screen.height); // Spielmenü dahinter komplett sperren
GUI.Box(r, GUIContent.none, windowBox); GUI.Box(r, GUIContent.none, windowBox);
string title = reconnecting ? "RECONNECTING" : mp.DisconnectTitle; string title = reconnecting
? ((mp.ReconnectMessage ?? "").StartsWith("Switching") ? "SWITCHING SERVER" : "RECONNECTING")
: mp.DisconnectTitle;
bool bad = !reconnecting && title != "DISCONNECTED"; bool bad = !reconnecting && title != "DISCONNECTED";
GUI.DrawTexture(new Rect(r.x, r.y, r.width, 4), bad ? texDanger : texAccent); GUI.DrawTexture(new Rect(r.x, r.y, r.width, 4), bad ? texDanger : texAccent);
+1
View File
@@ -81,6 +81,7 @@
<Compile Include="ControlSync.cs" /> <Compile Include="ControlSync.cs" />
<Compile Include="Toasts.cs" /> <Compile Include="Toasts.cs" />
<Compile Include="PlayerNeeds.cs" /> <Compile Include="PlayerNeeds.cs" />
<Compile Include="Favorites.cs" />
<Compile Include="MpCommand.cs" /> <Compile Include="MpCommand.cs" />
<Compile Include="Commands.cs" /> <Compile Include="Commands.cs" />
<Compile Include="MscoLog.cs" /> <Compile Include="MscoLog.cs" />
+47
View File
@@ -1021,6 +1021,53 @@ namespace MSCO
public int ReconnectAttempt { get { return reconnectAttempts; } } public int ReconnectAttempt { get { return reconnectAttempts; } }
public int ReconnectMaxAttempts { get { return MaxReconnectAttempts; } } public int ReconnectMaxAttempts { get { return MaxReconnectAttempts; } }
/// <summary>Server, mit dem man gerade verbunden ist (dedizierter Server), sonst null.</summary>
public string CurrentServerHost { get { return session != null && dedicated ? lastServerHost : null; } }
public int CurrentServerPort { get { return lastServerPort; } }
public string CurrentServerName { get { return lastServerName; } }
/// <summary>
/// Schnell den Server wechseln: Favorit per Kurzname (oder host:port). Ist man gerade verbunden, wird wie beim
/// Neu-Verbinden nach einem Welt-Reset getrennt und danach automatisch mit dem neuen Server verbunden.
/// </summary>
public string SwitchServer(string target)
{
target = (target ?? "").Trim();
if (target.Length == 0) return "switch <nickname> (see 'fav')";
Favorites.Favorite fav = Favorites.Find(target);
string host, name;
int port;
if (fav != null) { host = fav.Host; port = fav.Port; name = string.IsNullOrEmpty(fav.ServerName) ? fav.Nickname : fav.ServerName; }
else if (ServerBrowser.TryParseAddress(target, out host, out port)) name = null;
else return "No favorite called '" + target + "' - type 'fav' to see yours";
if (session != null && dedicated && string.Equals(lastServerHost, host, System.StringComparison.OrdinalIgnoreCase) && lastServerPort == port)
return "You are already on " + (fav != null ? fav.Nickname : host + ":" + port);
string label = fav != null ? fav.Nickname : host + ":" + port;
if (session == null)
{
if (!MenuHelper.InMenu) return "Go to the main menu first (or join a server) to switch";
JoinServer(host, port, name);
return "Connecting to " + label + " ...";
}
// Verbunden: trennen und danach automatisch mit dem neuen Server verbinden (übersteht das Neuladen der Mods)
lastServerHost = host;
lastServerPort = port;
lastServerName = name;
lastServerMax = 0;
serverReason = null;
reconnectAttempts = 0;
reconnectMessage = "Switching to " + label + " ...";
centerMessage = reconnectMessage;
centerMessageUntil = Time.realtimeSinceStartup + 2f;
session.Close("Switching server");
if (MenuHelper.InGame) reconnectHoldUntil = Time.realtimeSinceStartup + 0.8f; // kurz die Meldung zeigen
else OnSessionEnded("Switching server");
return reconnectMessage;
}
/// <summary>Automatisches Neu-Verbinden abbrechen (Knopf im Reconnect-Fenster).</summary> /// <summary>Automatisches Neu-Verbinden abbrechen (Knopf im Reconnect-Fenster).</summary>
public void CancelReconnect() public void CancelReconnect()
{ {