Crisp launcher (sizes and fonts scaled in screen pixels instead of a GUI matrix), fps command and display, fewer hitches (staggered scans, shared rigidbody scan, crash-damage mesh reads only after impacts, rarer vehicle fx lookups, cached display prefs)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,13 @@
|
|||||||
|
|
||||||
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`).
|
||||||
|
|
||||||
|
**Scharfe Oberfläche, FPS, Leistung**
|
||||||
|
- Launcher wird in voller Auflösung gezeichnet (Schrift und Kanten scharf statt hochgezogen/verpixelt)
|
||||||
|
- `fps` in der F7-Konsole: FPS-Anzeige oben rechts (grün/gelb/rot), Konsole zeigt auch das längste Bild (Ruckler)
|
||||||
|
- Weniger Ruckler: Sync-Teile suchen nach dem Laden nicht mehr alle im selben Frame, gemeinsame Suche nach Rigidbodys,
|
||||||
|
Unfallschäden werden nur noch nach einem Aufprall geprüft (vorher jede Sekunde große Mesh-Kopien), Fahrzeug-Effekte
|
||||||
|
schlagen ihre Bauteile seltener nach, Ping-/FPS-Anzeige ohne Registry-Zugriff pro Bild
|
||||||
|
|
||||||
**Launcher im Vollbild**
|
**Launcher im Vollbild**
|
||||||
- Der MSCO-Launcher füllt das ganze Hauptmenü und **skaliert automatisch** mit der Auflösung; Listen wachsen mit dem
|
- Der MSCO-Launcher füllt das ganze Hauptmenü und **skaliert automatisch** mit der Auflösung; Listen wachsen mit dem
|
||||||
Platz (keine abgeschnittenen Knöpfe mehr). Das Spielmenü dahinter (Logo, Farbauswahl, MP3 …) ist komplett verdeckt
|
Platz (keine abgeschnittenen Knöpfe mehr). Das Spielmenü dahinter (Logo, Farbauswahl, MP3 …) ist komplett verdeckt
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ namespace MSCO
|
|||||||
"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" +
|
||||||
"ping [on|off] - show your ping to the server (toggle)\n" +
|
"ping [on|off] - show your ping to the server (toggle)\n" +
|
||||||
|
"fps [on|off] - show the frames per second (toggle)\n" +
|
||||||
"/admin - admin menu (kick / ban / teleport / cheats)\n" +
|
"/admin - admin menu (kick / ban / teleport / cheats)\n" +
|
||||||
"vehicles | rig - debug info about vehicles / player models\n" +
|
"vehicles | rig - debug info about vehicles / player models\n" +
|
||||||
"debug - toggle sync debug output\n" +
|
"debug - toggle sync debug output\n" +
|
||||||
@@ -112,6 +113,12 @@ namespace MSCO
|
|||||||
else mp.ShowPing = !mp.ShowPing;
|
else mp.ShowPing = !mp.ShowPing;
|
||||||
print("Ping: " + mp.PingText + " (display " + (mp.ShowPing ? "on" : "off") + ")");
|
print("Ping: " + mp.PingText + " (display " + (mp.ShowPing ? "on" : "off") + ")");
|
||||||
break;
|
break;
|
||||||
|
case "fps":
|
||||||
|
// "fps" schaltet die Anzeige um, "fps on/off" setzt sie
|
||||||
|
if (args.Length > 1) mp.ShowFps = args[1].ToLower() == "on" || args[1] == "1";
|
||||||
|
else mp.ShowFps = !mp.ShowFps;
|
||||||
|
print("FPS: " + mp.FpsText + " (display " + (mp.ShowFps ? "on" : "off") + ")");
|
||||||
|
break;
|
||||||
case "admin":
|
case "admin":
|
||||||
case "/admin":
|
case "/admin":
|
||||||
mp.OpenAdminMenu();
|
mp.OpenAdminMenu();
|
||||||
|
|||||||
+2
-1
@@ -60,11 +60,12 @@ namespace MSCO
|
|||||||
{
|
{
|
||||||
controls.Clear();
|
controls.Clear();
|
||||||
scanned.Clear();
|
scanned.Clear();
|
||||||
nextScan = 0f;
|
nextScan = -1f; // erster Suchlauf verteilt, siehe Update
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(ObjectSync objects, int localId, Vector3 playerPos, Action<MsgType, byte[]> send)
|
public void Update(ObjectSync objects, int localId, Vector3 playerPos, Action<MsgType, byte[]> send)
|
||||||
{
|
{
|
||||||
|
if (nextScan < 0f) nextScan = Time.time + 2.4f; // nicht alle Sync-Teile im selben Frame suchen lassen
|
||||||
if (Time.time >= nextScan)
|
if (Time.time >= nextScan)
|
||||||
{
|
{
|
||||||
nextScan = Time.time + ScanInterval;
|
nextScan = Time.time + ScanInterval;
|
||||||
|
|||||||
+34
-8
@@ -14,8 +14,10 @@ namespace MSCO
|
|||||||
public class DamageSync
|
public class DamageSync
|
||||||
{
|
{
|
||||||
const float ScanInterval = 10f;
|
const float ScanInterval = 10f;
|
||||||
const float CheckInterval = 1f; // Fahrzeuge, die wir fahren
|
const float CheckInterval = 0.5f; // so oft nach einem Aufprall prüfen
|
||||||
const float FreeCheckInterval = 5f; // geparkte Fahrzeuge (Unfall nur durch Anstoßen) seltener
|
const float ImpactWindow = 4f; // so lange nach einem Aufprall prüfen (Verformung läuft ein paar Frames)
|
||||||
|
const float ImpactDeltaV = 2.5f; // plötzliche Geschwindigkeitsänderung (m/s pro Frame) = Aufprall
|
||||||
|
const float SafetyCheckInterval = 30f; // sonst nur selten (z.B. Reparatur in der Werkstatt)
|
||||||
const float MinMove = 0.002f;
|
const float MinMove = 0.002f;
|
||||||
const int MaxPerMessage = 4000;
|
const int MaxPerMessage = 4000;
|
||||||
|
|
||||||
@@ -26,13 +28,18 @@ namespace MSCO
|
|||||||
public int Key;
|
public int Key;
|
||||||
public string Root;
|
public string Root;
|
||||||
public MeshFilter Filter;
|
public MeshFilter Filter;
|
||||||
|
public Rigidbody Body; // Fahrzeug, zu dem das Mesh gehört
|
||||||
public Vector3[] Known; // zuletzt gesendet/empfangen
|
public Vector3[] Known; // zuletzt gesendet/empfangen
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly Dictionary<int, DamageMesh> meshes = new Dictionary<int, DamageMesh>();
|
readonly Dictionary<int, DamageMesh> meshes = new Dictionary<int, DamageMesh>();
|
||||||
readonly HashSet<MeshFilter> seen = new HashSet<MeshFilter>();
|
readonly HashSet<MeshFilter> seen = new HashSet<MeshFilter>();
|
||||||
readonly List<int> changed = new List<int>();
|
readonly List<int> changed = new List<int>();
|
||||||
float nextScan, nextCheck, nextFreeCheck;
|
float nextScan, nextCheck, nextSafetyCheck;
|
||||||
|
// Mesh-Daten lesen ist teuer (große Arrays, Speicher-Müll) - nur nach einem Aufprall
|
||||||
|
readonly Dictionary<Rigidbody, Vector3> lastVelocity = new Dictionary<Rigidbody, Vector3>();
|
||||||
|
readonly Dictionary<Rigidbody, float> lastImpact = new Dictionary<Rigidbody, float>();
|
||||||
|
readonly List<Rigidbody> bodies = new List<Rigidbody>();
|
||||||
static List<Type> types;
|
static List<Type> types;
|
||||||
|
|
||||||
public int Count { get { return meshes.Count; } }
|
public int Count { get { return meshes.Count; } }
|
||||||
@@ -41,27 +48,44 @@ namespace MSCO
|
|||||||
{
|
{
|
||||||
meshes.Clear();
|
meshes.Clear();
|
||||||
seen.Clear();
|
seen.Clear();
|
||||||
nextScan = 0f;
|
lastVelocity.Clear();
|
||||||
|
lastImpact.Clear();
|
||||||
|
bodies.Clear();
|
||||||
|
nextScan = -1f; // erster Suchlauf verteilt, siehe Update
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(ObjectSync objects, int localId, Action<MsgType, byte[]> send)
|
public void Update(ObjectSync objects, int localId, Action<MsgType, byte[]> send)
|
||||||
{
|
{
|
||||||
|
if (nextScan < 0f) nextScan = Time.time + 1.0f; // nicht alle Sync-Teile im selben Frame suchen lassen
|
||||||
if (Time.time >= nextScan)
|
if (Time.time >= nextScan)
|
||||||
{
|
{
|
||||||
nextScan = Time.time + ScanInterval;
|
nextScan = Time.time + ScanInterval;
|
||||||
Scan();
|
Scan();
|
||||||
}
|
}
|
||||||
|
// Aufprall erkennen: Geschwindigkeit ändert sich schlagartig (billig, jedes Frame)
|
||||||
|
for (int i = 0; i < bodies.Count; i++)
|
||||||
|
{
|
||||||
|
Rigidbody rb = bodies[i];
|
||||||
|
if (rb == null || rb.isKinematic) continue;
|
||||||
|
Vector3 v = rb.velocity, before;
|
||||||
|
if (lastVelocity.TryGetValue(rb, out before) && (v - before).sqrMagnitude > ImpactDeltaV * ImpactDeltaV)
|
||||||
|
lastImpact[rb] = Time.time;
|
||||||
|
lastVelocity[rb] = v;
|
||||||
|
}
|
||||||
|
|
||||||
if (Time.time < nextCheck) return;
|
if (Time.time < nextCheck) return;
|
||||||
nextCheck = Time.time + CheckInterval;
|
nextCheck = Time.time + CheckInterval;
|
||||||
bool checkFree = Time.time >= nextFreeCheck;
|
bool safety = Time.time >= nextSafetyCheck;
|
||||||
if (checkFree) nextFreeCheck = Time.time + FreeCheckInterval;
|
if (safety) nextSafetyCheck = Time.time + SafetyCheckInterval;
|
||||||
|
|
||||||
foreach (DamageMesh m in meshes.Values)
|
foreach (DamageMesh m in meshes.Values)
|
||||||
{
|
{
|
||||||
if (m.Filter == null) continue;
|
if (m.Filter == null) continue;
|
||||||
int owner = objects.VehicleOwner(m.Root);
|
int owner = objects.VehicleOwner(m.Root);
|
||||||
if (owner != SyncedBody.NoOwner && owner != localId) continue; // der Fahrer schickt die Schäden
|
if (owner != SyncedBody.NoOwner && owner != localId) continue; // der Fahrer schickt die Schäden
|
||||||
if (owner == SyncedBody.NoOwner && !checkFree) continue;
|
float impact;
|
||||||
|
bool recentImpact = m.Body != null && lastImpact.TryGetValue(m.Body, out impact) && Time.time - impact < ImpactWindow;
|
||||||
|
if (!recentImpact && !safety) continue;
|
||||||
|
|
||||||
Mesh mesh = m.Filter.sharedMesh;
|
Mesh mesh = m.Filter.sharedMesh;
|
||||||
if (mesh == null) continue;
|
if (mesh == null) continue;
|
||||||
@@ -164,7 +188,9 @@ namespace MSCO
|
|||||||
if (mesh == null || mesh.vertexCount == 0 || mesh.vertexCount > 65000) return;
|
if (mesh == null || mesh.vertexCount == 0 || mesh.vertexCount > 65000) return;
|
||||||
int key = Hash(FsmSync.PathOf(mf.transform));
|
int key = Hash(FsmSync.PathOf(mf.transform));
|
||||||
if (meshes.ContainsKey(key)) return; // nicht eindeutig
|
if (meshes.ContainsKey(key)) return; // nicht eindeutig
|
||||||
meshes[key] = new DamageMesh { Key = key, Root = mf.transform.root.name, Filter = mf, Known = mesh.vertices };
|
Rigidbody body = mf.transform.root.GetComponent<Rigidbody>();
|
||||||
|
meshes[key] = new DamageMesh { Key = key, Root = mf.transform.root.name, Filter = mf, Body = body, Known = mesh.vertices };
|
||||||
|
if (body != null && !bodies.Contains(body)) bodies.Add(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsVehicle(string root)
|
static bool IsVehicle(string root)
|
||||||
|
|||||||
+2
-1
@@ -50,11 +50,12 @@ namespace MSCO
|
|||||||
foreach (Hinge h in hinges.Values) StopDriving(h);
|
foreach (Hinge h in hinges.Values) StopDriving(h);
|
||||||
hinges.Clear();
|
hinges.Clear();
|
||||||
seen.Clear();
|
seen.Clear();
|
||||||
nextScan = 0f;
|
nextScan = -1f; // erster Suchlauf verteilt, siehe Update
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(ObjectSync objects, int localId, Vector3 playerPos, float dt, Action<MsgType, byte[]> send)
|
public void Update(ObjectSync objects, int localId, Vector3 playerPos, float dt, Action<MsgType, byte[]> send)
|
||||||
{
|
{
|
||||||
|
if (nextScan < 0f) nextScan = Time.time + 1.7f; // nicht alle Sync-Teile im selben Frame suchen lassen
|
||||||
if (Time.time >= nextScan)
|
if (Time.time >= nextScan)
|
||||||
{
|
{
|
||||||
nextScan = Time.time + ScanInterval;
|
nextScan = Time.time + ScanInterval;
|
||||||
|
|||||||
+215
-210
@@ -19,9 +19,16 @@ namespace MSCO
|
|||||||
const float SidebarWidth = 240f;
|
const float SidebarWidth = 240f;
|
||||||
const float StatusHeight = 40f;
|
const float StatusHeight = 40f;
|
||||||
const float MaxContentWidth = 1100f;
|
const float MaxContentWidth = 1100f;
|
||||||
float vw, vh, uiScale = 1f; // virtuelle Bildschirmgröße (Einheiten vor der Skalierung)
|
float vw, vh; // Bildschirmgröße in Pixeln
|
||||||
|
static float uiScale = 1f; // Skalierung passend zur Auflösung
|
||||||
|
float stylesScale = -1f; // für diese Skalierung wurden die Stile gebaut
|
||||||
float contentHeight = 400f; // Höhe des Inhaltsbereichs - Listen wachsen damit
|
float contentHeight = 400f; // Höhe des Inhaltsbereichs - Listen wachsen damit
|
||||||
|
|
||||||
|
// Maße (S) und Schriftgrößen/Abstände (P) werden direkt in Bildschirmpixeln berechnet - Schrift und Kanten
|
||||||
|
// werden so in voller Auflösung gezeichnet (scharf), statt ein kleines Bild hochzuziehen
|
||||||
|
static float S(float v) { return Mathf.Round(v * uiScale); }
|
||||||
|
static int P(int v) { return Mathf.Max(1, Mathf.RoundToInt(v * uiScale)); }
|
||||||
|
|
||||||
/// <summary>Höhe für eine Liste: was nach "reserved" für Überschriften/Knöpfe übrig bleibt.</summary>
|
/// <summary>Höhe für eine Liste: was nach "reserved" für Überschriften/Knöpfe übrig bleibt.</summary>
|
||||||
float ListHeight(float reserved, float min) { return Mathf.Max(min, contentHeight - reserved); }
|
float ListHeight(float reserved, float min) { return Mathf.Max(min, contentHeight - reserved); }
|
||||||
|
|
||||||
@@ -84,15 +91,12 @@ namespace MSCO
|
|||||||
|
|
||||||
public void Draw(MultiplayerManager mp)
|
public void Draw(MultiplayerManager mp)
|
||||||
{
|
{
|
||||||
EnsureStyles();
|
|
||||||
uiScale = Mathf.Clamp(Mathf.Min(Screen.height / RefHeight, Screen.width / RefWidth), MinScale, MaxScale);
|
uiScale = Mathf.Clamp(Mathf.Min(Screen.height / RefHeight, Screen.width / RefWidth), MinScale, MaxScale);
|
||||||
vw = Screen.width / uiScale;
|
EnsureStyles(); // baut die Stile neu, wenn sich die Skalierung ändert (Auflösung gewechselt)
|
||||||
vh = Screen.height / uiScale;
|
vw = Screen.width;
|
||||||
|
vh = Screen.height;
|
||||||
ScreenRect = new Rect(0, 0, Screen.width, Screen.height);
|
ScreenRect = new Rect(0, 0, Screen.width, Screen.height);
|
||||||
Matrix4x4 previous = GUI.matrix;
|
DrawScaled(mp);
|
||||||
GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(uiScale, uiScale, 1f));
|
|
||||||
try { DrawScaled(mp); }
|
|
||||||
finally { GUI.matrix = previous; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawScaled(MultiplayerManager mp)
|
void DrawScaled(MultiplayerManager mp)
|
||||||
@@ -109,12 +113,12 @@ namespace MSCO
|
|||||||
var window = new Rect(0, 0, vw, vh);
|
var window = new Rect(0, 0, vw, vh);
|
||||||
GUI.Box(window, GUIContent.none, windowBox);
|
GUI.Box(window, GUIContent.none, windowBox);
|
||||||
|
|
||||||
DrawSidebar(new Rect(0, 0, SidebarWidth, vh - StatusHeight));
|
DrawSidebar(new Rect(0, 0, S(SidebarWidth), vh - S(StatusHeight)));
|
||||||
|
|
||||||
// Inhalt mittig im freien Bereich, nicht beliebig breit (lesbar bleiben)
|
// Inhalt mittig im freien Bereich, nicht beliebig breit (lesbar bleiben)
|
||||||
float free = vw - SidebarWidth;
|
float free = vw - S(SidebarWidth);
|
||||||
float width = Mathf.Min(MaxContentWidth, free - 96f);
|
float width = Mathf.Min(S(MaxContentWidth), free - S(96f));
|
||||||
var content = new Rect(SidebarWidth + (free - width) / 2f, 40f, width, vh - StatusHeight - 72f);
|
var content = new Rect(S(SidebarWidth) + Mathf.Round((free - width) / 2f), S(40f), width, vh - S(StatusHeight) - S(72f));
|
||||||
contentHeight = content.height;
|
contentHeight = content.height;
|
||||||
GUILayout.BeginArea(content);
|
GUILayout.BeginArea(content);
|
||||||
if (versionWarning) DrawVersionWarning(mp);
|
if (versionWarning) DrawVersionWarning(mp);
|
||||||
@@ -125,7 +129,7 @@ namespace MSCO
|
|||||||
else DrawServerBrowser(mp);
|
else DrawServerBrowser(mp);
|
||||||
GUILayout.EndArea();
|
GUILayout.EndArea();
|
||||||
|
|
||||||
DrawStatusBar(mp, new Rect(0, vh - StatusHeight, vw, StatusHeight));
|
DrawStatusBar(mp, new Rect(0, vh - S(StatusHeight), vw, S(StatusHeight)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------- Bereiche
|
// ---------------------------------------------------------------- Bereiche
|
||||||
@@ -135,38 +139,38 @@ namespace MSCO
|
|||||||
GUI.Box(r, GUIContent.none, sidebarBox);
|
GUI.Box(r, GUIContent.none, sidebarBox);
|
||||||
// Logo + Schriftzug
|
// Logo + Schriftzug
|
||||||
Texture2D logo = Branding.LogoTexture;
|
Texture2D logo = Branding.LogoTexture;
|
||||||
float textX = r.x + 22;
|
float textX = r.x + S(22);
|
||||||
if (logo != null)
|
if (logo != null)
|
||||||
{
|
{
|
||||||
GUI.DrawTexture(new Rect(r.x + 20, r.y + 20, 44, 44), logo);
|
GUI.DrawTexture(new Rect(r.x + S(20), r.y + S(20), S(44), S(44)), logo);
|
||||||
textX = r.x + 72;
|
textX = r.x + S(72);
|
||||||
}
|
}
|
||||||
GUI.Label(new Rect(textX, r.y + 24, r.xMax - textX, 40), "MSCO", logoStyle);
|
GUI.Label(new Rect(textX, r.y + S(24), r.xMax - textX, S(40)), "MSCO", logoStyle);
|
||||||
GUI.Label(new Rect(r.x + 22, r.y + 70, r.width - 30, 20), "MY SUMMER CAR ONLINE", taglineStyle);
|
GUI.Label(new Rect(r.x + S(22), r.y + S(70), r.width - S(30), S(20)), "MY SUMMER CAR ONLINE", taglineStyle);
|
||||||
GUI.DrawTexture(new Rect(r.x + 20, r.y + 98, r.width - 40, 1), texDivider);
|
GUI.DrawTexture(new Rect(r.x + S(20), r.y + S(98), r.width - S(40), S(1)), texDivider);
|
||||||
|
|
||||||
float y = r.y + 110;
|
float y = r.y + S(110);
|
||||||
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, S(42)), "P2P", page == Page.P2P)) page = Page.P2P;
|
||||||
y += 44;
|
y += S(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, S(42)), "Server Browser", page == Page.ServerBrowser)) page = Page.ServerBrowser;
|
||||||
y += 44;
|
y += S(44);
|
||||||
int favCount = Favorites.All.Count;
|
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;
|
if (NavButton(new Rect(r.x, y, r.width, S(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)
|
||||||
{
|
{
|
||||||
if (GUI.Button(new Rect(r.x + 16, r.yMax - 118, r.width - 32, 36), "QUIT GAME?", dangerStyle)) Application.Quit();
|
if (GUI.Button(new Rect(r.x + S(16), r.yMax - S(118), r.width - S(32), S(36)), "QUIT GAME?", dangerStyle)) Application.Quit();
|
||||||
if (GUI.Button(new Rect(r.x + 16, r.yMax - 76, r.width - 32, 30), "CANCEL", tabStyle)) quitConfirm = false;
|
if (GUI.Button(new Rect(r.x + S(16), r.yMax - S(76), r.width - S(32), S(30)), "CANCEL", tabStyle)) quitConfirm = false;
|
||||||
}
|
}
|
||||||
else if (GUI.Button(new Rect(r.x + 16, r.yMax - 76, r.width - 32, 36), "QUIT", tabStyle)) quitConfirm = true;
|
else if (GUI.Button(new Rect(r.x + S(16), r.yMax - S(76), r.width - S(32), S(36)), "QUIT", tabStyle)) quitConfirm = true;
|
||||||
|
|
||||||
GUI.Label(new Rect(r.x + 24, r.yMax - 30, r.width - 48, 20), "v" + MSCO.ModVersion, taglineStyle);
|
GUI.Label(new Rect(r.x + S(24), r.yMax - S(30), r.width - S(48), S(20)), "v" + MSCO.ModVersion, taglineStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NavButton(Rect r, string text, bool active)
|
bool NavButton(Rect r, string text, bool active)
|
||||||
{
|
{
|
||||||
if (active) GUI.Box(new Rect(r.x + 4, r.y + 8, 4, r.height - 16), GUIContent.none, accentBox); // Akzentbalken links
|
if (active) GUI.Box(new Rect(r.x + S(4), r.y + S(8), S(4), r.height - S(16)), GUIContent.none, accentBox); // Akzentbalken links
|
||||||
return GUI.Button(r, text, active ? navActiveStyle : navStyle);
|
return GUI.Button(r, text, active ? navActiveStyle : navStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,13 +179,13 @@ namespace MSCO
|
|||||||
GUILayout.Label("P2P", titleStyle);
|
GUILayout.Label("P2P", titleStyle);
|
||||||
GUILayout.Label("Host a game and invite up to " + (MultiplayerManager.MaxPlayers - 1) +
|
GUILayout.Label("Host a game and invite up to " + (MultiplayerManager.MaxPlayers - 1) +
|
||||||
" friends through Steam - continue your own save or start a new game.", textStyle);
|
" friends through Steam - continue your own save or start a new game.", textStyle);
|
||||||
GUILayout.Space(18);
|
GUILayout.Space(S(18));
|
||||||
|
|
||||||
if (mp.SteamAvailable)
|
if (mp.SteamAvailable)
|
||||||
{
|
{
|
||||||
if (GUILayout.Button("HOST GAME", primaryStyle, GUILayout.Height(46), GUILayout.Width(250)))
|
if (GUILayout.Button("HOST GAME", primaryStyle, GUILayout.Height(S(46)), GUILayout.Width(S(250))))
|
||||||
mp.HostSteam();
|
mp.HostSteam();
|
||||||
GUILayout.Space(14);
|
GUILayout.Space(S(14));
|
||||||
GUILayout.Label("To join a friend: accept their invite in Steam, or right-click them in your " +
|
GUILayout.Label("To join a friend: accept their invite in Steam, or right-click them in your " +
|
||||||
"Steam friends list and choose \"Join Game\".", textStyle);
|
"Steam friends list and choose \"Join Game\".", textStyle);
|
||||||
}
|
}
|
||||||
@@ -219,26 +223,26 @@ namespace MSCO
|
|||||||
GUILayout.BeginHorizontal();
|
GUILayout.BeginHorizontal();
|
||||||
// Titel darf nicht vom REFRESH-Button zusammengedrückt werden (sonst Zeilenumbruch)
|
// Titel darf nicht vom REFRESH-Button zusammengedrückt werden (sonst Zeilenumbruch)
|
||||||
GUILayout.Label("Server Browser", titleStyle, GUILayout.ExpandWidth(true));
|
GUILayout.Label("Server Browser", titleStyle, GUILayout.ExpandWidth(true));
|
||||||
if (GUILayout.Button(browser.Loading ? "LOADING..." : "REFRESH", tabStyle, GUILayout.Height(28), GUILayout.Width(110)))
|
if (GUILayout.Button(browser.Loading ? "LOADING..." : "REFRESH", tabStyle, GUILayout.Height(S(28)), GUILayout.Width(S(110))))
|
||||||
browser.Refresh(mp);
|
browser.Refresh(mp);
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
// Suche + Filter
|
// Suche + Filter
|
||||||
GUILayout.BeginHorizontal();
|
GUILayout.BeginHorizontal();
|
||||||
searchInput = GUILayout.TextField(searchInput, 40, fieldStyle, GUILayout.Height(26), GUILayout.Width(170));
|
searchInput = GUILayout.TextField(searchInput, 40, fieldStyle, GUILayout.Height(S(26)), GUILayout.Width(S(170)));
|
||||||
if (string.IsNullOrEmpty(searchInput))
|
if (string.IsNullOrEmpty(searchInput))
|
||||||
{
|
{
|
||||||
Rect field = GUILayoutUtility.GetLastRect();
|
Rect field = GUILayoutUtility.GetLastRect();
|
||||||
GUI.Label(new Rect(field.x + 10, field.y, field.width, field.height), "Search...", placeholderStyle);
|
GUI.Label(new Rect(field.x + S(10), field.y, field.width, field.height), "Search...", placeholderStyle);
|
||||||
}
|
}
|
||||||
GUILayout.Space(12);
|
GUILayout.Space(S(12));
|
||||||
showSteam = Chip(showSteam, "STEAM");
|
showSteam = Chip(showSteam, "STEAM");
|
||||||
GUILayout.Space(6);
|
GUILayout.Space(S(6));
|
||||||
showNonSteam = Chip(showNonSteam, "NON-STEAM");
|
showNonSteam = Chip(showNonSteam, "NON-STEAM");
|
||||||
GUILayout.Space(6);
|
GUILayout.Space(S(6));
|
||||||
hideFull = Chip(hideFull, "HIDE FULL");
|
hideFull = Chip(hideFull, "HIDE FULL");
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
GUILayout.Space(6);
|
GUILayout.Space(S(6));
|
||||||
|
|
||||||
string search = (searchInput ?? "").Trim().ToLower();
|
string search = (searchInput ?? "").Trim().ToLower();
|
||||||
if (shownServers == null || Event.current.type == EventType.Layout)
|
if (shownServers == null || Event.current.type == EventType.Layout)
|
||||||
@@ -251,35 +255,35 @@ namespace MSCO
|
|||||||
string shownError = Event.current.type == EventType.Layout ? (layoutError = browser.Error) : layoutError;
|
string shownError = Event.current.type == EventType.Layout ? (layoutError = browser.Error) : layoutError;
|
||||||
|
|
||||||
// Tabellenkopf
|
// Tabellenkopf
|
||||||
Rect header = GUILayoutUtility.GetRect(10, 26, GUILayout.ExpandWidth(true));
|
Rect header = GUILayoutUtility.GetRect(S(10), S(26), GUILayout.ExpandWidth(true));
|
||||||
GUI.Box(header, GUIContent.none, rowBox);
|
GUI.Box(header, GUIContent.none, rowBox);
|
||||||
GUI.Label(new Rect(header.x + 12, header.y, header.width * 0.48f, header.height), "SERVER NAME", headerCellStyle);
|
GUI.Label(new Rect(header.x + S(12), header.y, header.width * 0.48f, header.height), "SERVER NAME", headerCellStyle);
|
||||||
GUI.Label(new Rect(header.x + header.width * 0.5f, header.y, 70, header.height), "PLAYERS", headerCellStyle);
|
GUI.Label(new Rect(header.x + header.width * 0.5f, header.y, S(70), header.height), "PLAYERS", headerCellStyle);
|
||||||
GUI.Label(new Rect(header.x + header.width * 0.62f, header.y, 70, header.height), "TYPE", headerCellStyle);
|
GUI.Label(new Rect(header.x + header.width * 0.62f, header.y, S(70), header.height), "TYPE", headerCellStyle);
|
||||||
GUI.Label(new Rect(header.x + header.width * 0.76f, header.y, 50, header.height), "PING", headerCellStyle);
|
GUI.Label(new Rect(header.x + header.width * 0.76f, header.y, S(50), header.height), "PING", headerCellStyle);
|
||||||
|
|
||||||
serverScroll = GUILayout.BeginScrollView(serverScroll, GUILayout.Height(ListHeight(230f, 140f)));
|
serverScroll = GUILayout.BeginScrollView(serverScroll, GUILayout.Height(ListHeight(S(230f), S(140f))));
|
||||||
if (shownError != null) GUILayout.Label(shownError, textStyle);
|
if (shownError != null) GUILayout.Label(shownError, textStyle);
|
||||||
if (servers.Count == 0)
|
if (servers.Count == 0)
|
||||||
GUILayout.Label(browser.Loading ? "Loading servers..." : all.Count > 0 ? "No servers match your filters." : "No servers online right now.", textStyle);
|
GUILayout.Label(browser.Loading ? "Loading servers..." : all.Count > 0 ? "No servers match your filters." : "No servers online right now.", textStyle);
|
||||||
foreach (ServerListEntry s in servers)
|
foreach (ServerListEntry s in servers)
|
||||||
{
|
{
|
||||||
Rect row = GUILayoutUtility.GetRect(10, 34, GUILayout.ExpandWidth(true));
|
Rect row = GUILayoutUtility.GetRect(S(10), S(34), GUILayout.ExpandWidth(true));
|
||||||
// Hervorgehobene Server (Keymaster-Admin) stehen oben - der Master liefert sie zuerst
|
// Hervorgehobene Server (Keymaster-Admin) stehen oben - der Master liefert sie zuerst
|
||||||
var rowRect = new Rect(row.x, row.y + 2, row.width, row.height - 4);
|
var rowRect = new Rect(row.x, row.y + S(2), row.width, row.height - S(4));
|
||||||
bool hover = rowRect.Contains(Event.current.mousePosition);
|
bool hover = rowRect.Contains(Event.current.mousePosition);
|
||||||
GUI.Box(rowRect, GUIContent.none, s.Featured ? featuredRowBox : hover ? rowHoverBox : rowBox);
|
GUI.Box(rowRect, GUIContent.none, s.Featured ? featuredRowBox : hover ? rowHoverBox : rowBox);
|
||||||
if (s.Featured) GUI.DrawTexture(new Rect(row.x, row.y + 8, 3, row.height - 16), texGold);
|
if (s.Featured) GUI.DrawTexture(new Rect(row.x, row.y + S(8), S(3), row.height - S(16)), texGold);
|
||||||
|
|
||||||
// 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 - S(58), row.y + S(7), S(20), S(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 + S(10), row.y + S(13), S(8), S(8)), s.Ping < 0 ? texPending : texOnline);
|
||||||
float nameX = row.x + 26;
|
float nameX = row.x + S(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 (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);
|
||||||
@@ -295,13 +299,13 @@ namespace MSCO
|
|||||||
GUI.Label(new Rect(nameX, row.y, row.x + row.width * 0.49f - nameX, row.height), s.Name, rowNameStyle);
|
GUI.Label(new Rect(nameX, row.y, row.x + row.width * 0.49f - nameX, row.height), s.Name, rowNameStyle);
|
||||||
// Spielerzahl mit Füllbalken (wie auf der Website)
|
// Spielerzahl mit Füllbalken (wie auf der Website)
|
||||||
float px = row.x + row.width * 0.5f;
|
float px = row.x + row.width * 0.5f;
|
||||||
GUI.Label(new Rect(px, row.y - 3, 70, row.height), s.Players + "/" + s.MaxPlayers, rowNameStyle);
|
GUI.Label(new Rect(px, row.y - S(3), S(70), row.height), s.Players + "/" + s.MaxPlayers, rowNameStyle);
|
||||||
float fill = s.MaxPlayers > 0 ? Mathf.Clamp01((float)s.Players / s.MaxPlayers) : 0f;
|
float fill = s.MaxPlayers > 0 ? Mathf.Clamp01((float)s.Players / s.MaxPlayers) : 0f;
|
||||||
GUI.DrawTexture(new Rect(px, row.y + 24, 48, 3), texBarBack);
|
GUI.DrawTexture(new Rect(px, row.y + S(24), S(48), S(3)), texBarBack);
|
||||||
GUI.DrawTexture(new Rect(px, row.y + 24, Mathf.Max(2f, 48 * fill), 3), fill >= 1f ? texBarFull : texBarFill);
|
GUI.DrawTexture(new Rect(px, row.y + S(24), Mathf.Max(S(2f), S(48) * fill), S(3)), fill >= 1f ? texBarFull : texBarFill);
|
||||||
Pill(row.x + row.width * 0.62f, row, s.RequireSteam ? "STEAM" : "NO STEAM", s.RequireSteam ? pillStyle : pillMutedStyle);
|
Pill(row.x + row.width * 0.62f, row, s.RequireSteam ? "STEAM" : "NO STEAM", s.RequireSteam ? pillStyle : pillMutedStyle);
|
||||||
GUI.Label(new Rect(row.x + row.width * 0.76f, row.y, 60, row.height), s.Ping < 0 ? "..." : s.Ping + " ms", PingStyle(s.Ping));
|
GUI.Label(new Rect(row.x + row.width * 0.76f, row.y, S(60), row.height), s.Ping < 0 ? "..." : s.Ping + " ms", PingStyle(s.Ping));
|
||||||
GUI.Label(new Rect(row.xMax - 30, row.y, 20, row.height), "›", headerCellStyle); // Hinweis: Profil öffnen
|
GUI.Label(new Rect(row.xMax - S(30), row.y, S(20), row.height), "›", headerCellStyle); // Hinweis: Profil öffnen
|
||||||
}
|
}
|
||||||
GUILayout.EndScrollView();
|
GUILayout.EndScrollView();
|
||||||
|
|
||||||
@@ -310,18 +314,18 @@ namespace MSCO
|
|||||||
if (!mp.SteamAvailable)
|
if (!mp.SteamAvailable)
|
||||||
{
|
{
|
||||||
// Ohne Steam: eigener Name (nur für Non-Steam-Server)
|
// Ohne Steam: eigener Name (nur für Non-Steam-Server)
|
||||||
GUILayout.BeginVertical(GUILayout.Width(150));
|
GUILayout.BeginVertical(GUILayout.Width(S(150)));
|
||||||
GUILayout.Label("YOUR NAME", captionStyle);
|
GUILayout.Label("YOUR NAME", captionStyle);
|
||||||
DrawNameField(mp, 150);
|
DrawNameField(mp, 150);
|
||||||
GUILayout.EndVertical();
|
GUILayout.EndVertical();
|
||||||
GUILayout.Space(10);
|
GUILayout.Space(S(10));
|
||||||
}
|
}
|
||||||
GUILayout.BeginVertical();
|
GUILayout.BeginVertical();
|
||||||
GUILayout.Label("DIRECT CONNECT", captionStyle);
|
GUILayout.Label("DIRECT CONNECT", captionStyle);
|
||||||
GUILayout.BeginHorizontal();
|
GUILayout.BeginHorizontal();
|
||||||
directInput = GUILayout.TextField(directInput, fieldStyle, GUILayout.Height(34));
|
directInput = GUILayout.TextField(directInput, fieldStyle, GUILayout.Height(S(34)));
|
||||||
GUILayout.Space(10);
|
GUILayout.Space(S(10));
|
||||||
if (GUILayout.Button("CONNECT", primaryStyle, GUILayout.Height(34), GUILayout.Width(110)))
|
if (GUILayout.Button("CONNECT", primaryStyle, GUILayout.Height(S(34)), GUILayout.Width(S(110))))
|
||||||
{
|
{
|
||||||
string host;
|
string host;
|
||||||
int port;
|
int port;
|
||||||
@@ -344,7 +348,7 @@ namespace MSCO
|
|||||||
void DrawNameField(MultiplayerManager mp, float width)
|
void DrawNameField(MultiplayerManager mp, float width)
|
||||||
{
|
{
|
||||||
if (nameInput == null) nameInput = mp.PlayerName;
|
if (nameInput == null) nameInput = mp.PlayerName;
|
||||||
string edited = GUILayout.TextField(nameInput, 24, fieldStyle, GUILayout.Height(34), GUILayout.Width(width));
|
string edited = GUILayout.TextField(nameInput, 24, fieldStyle, GUILayout.Height(S(34)), GUILayout.Width(width));
|
||||||
if (edited != nameInput)
|
if (edited != nameInput)
|
||||||
{
|
{
|
||||||
nameInput = edited;
|
nameInput = edited;
|
||||||
@@ -383,40 +387,40 @@ namespace MSCO
|
|||||||
EnsureHearts();
|
EnsureHearts();
|
||||||
GUILayout.Label("Favorites", titleStyle);
|
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.Label("Give each server a nickname - switch in the game with /switch <nickname> in the chat or F7 console.", textStyle);
|
||||||
GUILayout.Space(8);
|
GUILayout.Space(S(8));
|
||||||
|
|
||||||
List<Favorites.Favorite> favs = Favorites.All;
|
List<Favorites.Favorite> favs = Favorites.All;
|
||||||
favoritesScroll = GUILayout.BeginScrollView(favoritesScroll, GUILayout.Height(ListHeight(190f, 160f)));
|
favoritesScroll = GUILayout.BeginScrollView(favoritesScroll, GUILayout.Height(ListHeight(S(190f), S(160f))));
|
||||||
if (favs.Count == 0)
|
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);
|
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;
|
Favorites.Favorite remove = null;
|
||||||
foreach (Favorites.Favorite f in favs)
|
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));
|
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.BeginHorizontal(rowBox, GUILayout.Height(S(44)));
|
||||||
GUILayout.Space(6);
|
GUILayout.Space(S(6));
|
||||||
|
|
||||||
// Herz (entfernen)
|
// Herz (entfernen)
|
||||||
Rect heart = GUILayoutUtility.GetRect(22, 22, GUILayout.Width(22), GUILayout.Height(40));
|
Rect heart = GUILayoutUtility.GetRect(S(22), S(22), GUILayout.Width(S(22)), GUILayout.Height(S(40)));
|
||||||
Rect heartIcon = new Rect(heart.x, heart.y + 10, 20, 20);
|
Rect heartIcon = new Rect(heart.x, heart.y + S(10), S(20), S(20));
|
||||||
GUI.DrawTexture(heartIcon, texHeartOn);
|
GUI.DrawTexture(heartIcon, texHeartOn);
|
||||||
if (GUI.Button(heartIcon, GUIContent.none, GUIStyle.none)) remove = f;
|
if (GUI.Button(heartIcon, GUIContent.none, GUIStyle.none)) remove = f;
|
||||||
GUILayout.Space(8);
|
GUILayout.Space(S(8));
|
||||||
|
|
||||||
// Kurzname bearbeiten
|
// Kurzname bearbeiten
|
||||||
string edit;
|
string edit;
|
||||||
if (!nicknameEdits.TryGetValue(f.Address, out edit)) edit = f.Nickname;
|
if (!nicknameEdits.TryGetValue(f.Address, out edit)) edit = f.Nickname;
|
||||||
GUILayout.BeginVertical(GUILayout.Width(150));
|
GUILayout.BeginVertical(GUILayout.Width(S(150)));
|
||||||
GUILayout.Space(7);
|
GUILayout.Space(S(7));
|
||||||
edit = GUILayout.TextField(edit, 20, fieldStyle, GUILayout.Height(28), GUILayout.Width(150));
|
edit = GUILayout.TextField(edit, 20, fieldStyle, GUILayout.Height(S(28)), GUILayout.Width(S(150)));
|
||||||
GUILayout.EndVertical();
|
GUILayout.EndVertical();
|
||||||
nicknameEdits[f.Address] = edit;
|
nicknameEdits[f.Address] = edit;
|
||||||
GUILayout.Space(6);
|
GUILayout.Space(S(6));
|
||||||
bool changed = Favorites.CleanNickname(edit) != f.Nickname;
|
bool changed = Favorites.CleanNickname(edit) != f.Nickname;
|
||||||
GUILayout.BeginVertical(GUILayout.Width(64));
|
GUILayout.BeginVertical(GUILayout.Width(S(64)));
|
||||||
GUILayout.Space(7);
|
GUILayout.Space(S(7));
|
||||||
GUI.enabled = changed;
|
GUI.enabled = changed;
|
||||||
if (GUILayout.Button("SAVE", tabStyle, GUILayout.Height(28), GUILayout.Width(64)))
|
if (GUILayout.Button("SAVE", tabStyle, GUILayout.Height(S(28)), GUILayout.Width(S(64))))
|
||||||
{
|
{
|
||||||
string error = Favorites.Set(edit, f.Host, f.Port, f.ServerName);
|
string error = Favorites.Set(edit, f.Host, f.Port, f.ServerName);
|
||||||
if (error != null) MscoLog.Warning(error);
|
if (error != null) MscoLog.Warning(error);
|
||||||
@@ -424,24 +428,24 @@ namespace MSCO
|
|||||||
}
|
}
|
||||||
GUI.enabled = true;
|
GUI.enabled = true;
|
||||||
GUILayout.EndVertical();
|
GUILayout.EndVertical();
|
||||||
GUILayout.Space(10);
|
GUILayout.Space(S(10));
|
||||||
|
|
||||||
// Server + Status
|
// Server + Status
|
||||||
GUILayout.BeginVertical();
|
GUILayout.BeginVertical();
|
||||||
GUILayout.Space(4);
|
GUILayout.Space(S(4));
|
||||||
GUILayout.Label(string.IsNullOrEmpty(f.ServerName) ? f.Address : f.ServerName, rowNameStyle);
|
GUILayout.Label(string.IsNullOrEmpty(f.ServerName) ? f.Address : f.ServerName, rowNameStyle);
|
||||||
GUILayout.Label(live == null ? f.Address + " · not listed / offline"
|
GUILayout.Label(live == null ? f.Address + " · not listed / offline"
|
||||||
: f.Address + " · " + live.Players + "/" + live.MaxPlayers + " · " + (live.Ping < 0 ? "..." : live.Ping + " ms"), textStyle);
|
: f.Address + " · " + live.Players + "/" + live.MaxPlayers + " · " + (live.Ping < 0 ? "..." : live.Ping + " ms"), textStyle);
|
||||||
GUILayout.EndVertical();
|
GUILayout.EndVertical();
|
||||||
GUILayout.FlexibleSpace();
|
GUILayout.FlexibleSpace();
|
||||||
|
|
||||||
GUILayout.BeginVertical(GUILayout.Width(90));
|
GUILayout.BeginVertical(GUILayout.Width(S(90)));
|
||||||
GUILayout.Space(7);
|
GUILayout.Space(S(7));
|
||||||
if (GUILayout.Button("JOIN", primaryStyle, GUILayout.Height(30), GUILayout.Width(90))) mp.SwitchServer(f.Nickname);
|
if (GUILayout.Button("JOIN", primaryStyle, GUILayout.Height(S(30)), GUILayout.Width(S(90)))) mp.SwitchServer(f.Nickname);
|
||||||
GUILayout.EndVertical();
|
GUILayout.EndVertical();
|
||||||
GUILayout.Space(6);
|
GUILayout.Space(S(6));
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
GUILayout.Space(4);
|
GUILayout.Space(S(4));
|
||||||
}
|
}
|
||||||
if (remove != null) { Favorites.Remove(remove); nicknameEdits.Remove(remove.Address); }
|
if (remove != null) { Favorites.Remove(remove); nicknameEdits.Remove(remove.Address); }
|
||||||
GUILayout.EndScrollView();
|
GUILayout.EndScrollView();
|
||||||
@@ -449,14 +453,14 @@ namespace MSCO
|
|||||||
GUILayout.FlexibleSpace();
|
GUILayout.FlexibleSpace();
|
||||||
GUILayout.Label("ADD BY ADDRESS", captionStyle);
|
GUILayout.Label("ADD BY ADDRESS", captionStyle);
|
||||||
GUILayout.BeginHorizontal();
|
GUILayout.BeginHorizontal();
|
||||||
favoriteAddInput = GUILayout.TextField(favoriteAddInput ?? "", 60, fieldStyle, GUILayout.Height(34));
|
favoriteAddInput = GUILayout.TextField(favoriteAddInput ?? "", 60, fieldStyle, GUILayout.Height(S(34)));
|
||||||
if (string.IsNullOrEmpty(favoriteAddInput))
|
if (string.IsNullOrEmpty(favoriteAddInput))
|
||||||
{
|
{
|
||||||
Rect field = GUILayoutUtility.GetLastRect();
|
Rect field = GUILayoutUtility.GetLastRect();
|
||||||
GUI.Label(new Rect(field.x + 10, field.y, field.width, field.height), "host:port", placeholderStyle);
|
GUI.Label(new Rect(field.x + S(10), field.y, field.width, field.height), "host:port", placeholderStyle);
|
||||||
}
|
}
|
||||||
GUILayout.Space(10);
|
GUILayout.Space(S(10));
|
||||||
if (GUILayout.Button("ADD", secondaryStyle, GUILayout.Height(34), GUILayout.Width(110)))
|
if (GUILayout.Button("ADD", secondaryStyle, GUILayout.Height(S(34)), GUILayout.Width(S(110))))
|
||||||
{
|
{
|
||||||
string host;
|
string host;
|
||||||
int port;
|
int port;
|
||||||
@@ -517,12 +521,12 @@ namespace MSCO
|
|||||||
/// <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)
|
||||||
{
|
{
|
||||||
if (GUILayout.Button("◂ BACK", tabStyle, GUILayout.Height(26), GUILayout.Width(90)))
|
if (GUILayout.Button("◂ BACK", tabStyle, GUILayout.Height(S(26)), GUILayout.Width(S(90))))
|
||||||
{
|
{
|
||||||
selectedServer = null;
|
selectedServer = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GUILayout.Space(8);
|
GUILayout.Space(S(8));
|
||||||
|
|
||||||
if (s == null)
|
if (s == null)
|
||||||
{
|
{
|
||||||
@@ -536,7 +540,7 @@ namespace MSCO
|
|||||||
GUILayout.BeginVertical();
|
GUILayout.BeginVertical();
|
||||||
GUILayout.Label(s.Name, titleStyle);
|
GUILayout.Label(s.Name, titleStyle);
|
||||||
GUILayout.BeginHorizontal();
|
GUILayout.BeginHorizontal();
|
||||||
Rect badgeRow = GUILayoutUtility.GetRect(10, 20, GUILayout.ExpandWidth(true));
|
Rect badgeRow = GUILayoutUtility.GetRect(S(10), S(20), GUILayout.ExpandWidth(true));
|
||||||
float bx = badgeRow.x;
|
float bx = badgeRow.x;
|
||||||
if (s.Featured) bx += Pill(bx, badgeRow, "FEATURED", pillFeaturedStyle);
|
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);
|
||||||
@@ -547,49 +551,49 @@ namespace MSCO
|
|||||||
if (!string.IsNullOrEmpty(tag) && tag != "featured") bx += Pill(bx, badgeRow, tag.ToUpper(), pillMutedStyle);
|
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(S(12));
|
||||||
Rect heartSlot = GUILayoutUtility.GetRect(44, 44, GUILayout.Width(44), GUILayout.Height(44));
|
Rect heartSlot = GUILayoutUtility.GetRect(S(44), S(44), GUILayout.Width(S(44)), GUILayout.Height(S(44)));
|
||||||
GUI.Box(heartSlot, GUIContent.none, rowBox);
|
GUI.Box(heartSlot, GUIContent.none, rowBox);
|
||||||
Heart(new Rect(heartSlot.x + 11, heartSlot.y + 11, 22, 22), s);
|
Heart(new Rect(heartSlot.x + S(11), heartSlot.y + S(11), S(22), S(22)), s);
|
||||||
GUILayout.Space(8);
|
GUILayout.Space(S(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(S(44)), GUILayout.Width(S(180))))
|
||||||
mp.JoinServer(s.Address, s.Port, s.Name, s.MaxPlayers);
|
mp.JoinServer(s.Address, s.Port, s.Name, s.MaxPlayers);
|
||||||
GUI.enabled = true;
|
GUI.enabled = true;
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
if (!string.IsNullOrEmpty(s.Description)) GUILayout.Label(s.Description, textStyle);
|
if (!string.IsNullOrEmpty(s.Description)) GUILayout.Label(s.Description, textStyle);
|
||||||
GUILayout.Space(10);
|
GUILayout.Space(S(10));
|
||||||
|
|
||||||
// Ohne Steam: Name wählen (sauber in einem eigenen Kasten)
|
// Ohne Steam: Name wählen (sauber in einem eigenen Kasten)
|
||||||
if (s.RequireSteam && !mp.SteamAvailable)
|
if (s.RequireSteam && !mp.SteamAvailable)
|
||||||
{
|
{
|
||||||
GUILayout.BeginHorizontal(rowBox, GUILayout.Height(40));
|
GUILayout.BeginHorizontal(rowBox, GUILayout.Height(S(40)));
|
||||||
GUILayout.Label("This server requires Steam - start the game through Steam to join.", textStyle);
|
GUILayout.Label("This server requires Steam - start the game through Steam to join.", textStyle);
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
GUILayout.Space(10);
|
GUILayout.Space(S(10));
|
||||||
}
|
}
|
||||||
else if (!mp.SteamAvailable)
|
else if (!mp.SteamAvailable)
|
||||||
{
|
{
|
||||||
GUILayout.BeginHorizontal(rowBox, GUILayout.Height(44));
|
GUILayout.BeginHorizontal(rowBox, GUILayout.Height(S(44)));
|
||||||
GUILayout.Space(6);
|
GUILayout.Space(S(6));
|
||||||
GUILayout.BeginVertical(GUILayout.Width(110));
|
GUILayout.BeginVertical(GUILayout.Width(S(110)));
|
||||||
GUILayout.Space(4);
|
GUILayout.Space(S(4));
|
||||||
GUILayout.Label("PLAYING AS", captionStyle);
|
GUILayout.Label("PLAYING AS", captionStyle);
|
||||||
GUILayout.Label("no Steam", textStyle);
|
GUILayout.Label("no Steam", textStyle);
|
||||||
GUILayout.EndVertical();
|
GUILayout.EndVertical();
|
||||||
GUILayout.BeginVertical();
|
GUILayout.BeginVertical();
|
||||||
GUILayout.Space(5);
|
GUILayout.Space(S(5));
|
||||||
DrawNameField(mp, 220);
|
DrawNameField(mp, 220);
|
||||||
GUILayout.EndVertical();
|
GUILayout.EndVertical();
|
||||||
GUILayout.FlexibleSpace();
|
GUILayout.FlexibleSpace();
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
GUILayout.Space(10);
|
GUILayout.Space(S(10));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Infos links, Spielerliste rechts
|
// Infos links, Spielerliste rechts
|
||||||
bool versionOk = s.Version == MSCO.ModVersion;
|
bool versionOk = s.Version == MSCO.ModVersion;
|
||||||
GUILayout.BeginHorizontal();
|
GUILayout.BeginHorizontal();
|
||||||
GUILayout.BeginVertical(GUILayout.Width(250));
|
GUILayout.BeginVertical(GUILayout.Width(S(250)));
|
||||||
InfoLine("HOSTED BY", string.IsNullOrEmpty(s.Owner) ? "unknown" : s.Owner, rowNameStyle);
|
InfoLine("HOSTED BY", string.IsNullOrEmpty(s.Owner) ? "unknown" : s.Owner, rowNameStyle);
|
||||||
InfoLine("VERSION", "v" + s.Version + (versionOk ? "" : " (you: v" + MSCO.ModVersion + ")"), versionOk ? rowNameStyle : badgeStyle);
|
InfoLine("VERSION", "v" + s.Version + (versionOk ? "" : " (you: v" + MSCO.ModVersion + ")"), versionOk ? rowNameStyle : badgeStyle);
|
||||||
InfoLine("STEAM", s.RequireSteam ? "Required" : "Not required", rowNameStyle);
|
InfoLine("STEAM", s.RequireSteam ? "Required" : "Not required", rowNameStyle);
|
||||||
@@ -597,20 +601,20 @@ namespace MSCO
|
|||||||
InfoLine("PING", s.Ping < 0 ? "-" : s.Ping + " ms", PingStyle(s.Ping));
|
InfoLine("PING", s.Ping < 0 ? "-" : s.Ping + " ms", PingStyle(s.Ping));
|
||||||
InfoLine("ADDRESS", s.Address + ":" + s.Port, rowNameStyle);
|
InfoLine("ADDRESS", s.Address + ":" + s.Port, rowNameStyle);
|
||||||
GUILayout.EndVertical();
|
GUILayout.EndVertical();
|
||||||
GUILayout.Space(16);
|
GUILayout.Space(S(16));
|
||||||
|
|
||||||
GUILayout.BeginVertical(rowBox, GUILayout.ExpandWidth(true), GUILayout.MinHeight(150));
|
GUILayout.BeginVertical(rowBox, GUILayout.ExpandWidth(true), GUILayout.MinHeight(S(150)));
|
||||||
GUILayout.Space(6);
|
GUILayout.Space(S(6));
|
||||||
GUILayout.Label("PLAYERS " + s.Players + " / " + s.MaxPlayers, captionStyle);
|
GUILayout.Label("PLAYERS " + s.Players + " / " + s.MaxPlayers, captionStyle);
|
||||||
profileScroll = GUILayout.BeginScrollView(profileScroll, GUILayout.Height(ListHeight(330f, 130f)));
|
profileScroll = GUILayout.BeginScrollView(profileScroll, GUILayout.Height(ListHeight(S(330f), S(130f))));
|
||||||
if (s.PlayerNames == null || s.PlayerNames.Count == 0)
|
if (s.PlayerNames == null || s.PlayerNames.Count == 0)
|
||||||
GUILayout.Label("Nobody online right now.", textStyle);
|
GUILayout.Label("Nobody online right now.", textStyle);
|
||||||
else
|
else
|
||||||
foreach (string name in s.PlayerNames)
|
foreach (string name in s.PlayerNames)
|
||||||
{
|
{
|
||||||
Rect line = GUILayoutUtility.GetRect(10, 24, GUILayout.ExpandWidth(true));
|
Rect line = GUILayoutUtility.GetRect(S(10), S(24), GUILayout.ExpandWidth(true));
|
||||||
GUI.DrawTexture(new Rect(line.x + 2, line.y + 8, 8, 8), texOnline);
|
GUI.DrawTexture(new Rect(line.x + S(2), line.y + S(8), S(8), S(8)), texOnline);
|
||||||
GUI.Label(new Rect(line.x + 18, line.y, line.width - 18, line.height), name, rowNameStyle);
|
GUI.Label(new Rect(line.x + S(18), line.y, line.width - S(18), line.height), name, rowNameStyle);
|
||||||
}
|
}
|
||||||
GUILayout.EndScrollView();
|
GUILayout.EndScrollView();
|
||||||
GUILayout.EndVertical();
|
GUILayout.EndVertical();
|
||||||
@@ -621,8 +625,8 @@ namespace MSCO
|
|||||||
/// <summary>Eine Info-Zeile: Bezeichnung links (grau), Wert rechts.</summary>
|
/// <summary>Eine Info-Zeile: Bezeichnung links (grau), Wert rechts.</summary>
|
||||||
void InfoLine(string caption, string value, GUIStyle valueStyle)
|
void InfoLine(string caption, string value, GUIStyle valueStyle)
|
||||||
{
|
{
|
||||||
GUILayout.BeginHorizontal(GUILayout.Height(26));
|
GUILayout.BeginHorizontal(GUILayout.Height(S(26)));
|
||||||
GUILayout.Label(caption, captionStyle, GUILayout.Width(100));
|
GUILayout.Label(caption, captionStyle, GUILayout.Width(S(100)));
|
||||||
GUILayout.Label(value, valueStyle);
|
GUILayout.Label(value, valueStyle);
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
}
|
}
|
||||||
@@ -631,14 +635,14 @@ namespace MSCO
|
|||||||
static float Pill(float x, Rect row, string text, GUIStyle style)
|
static float Pill(float x, Rect row, string text, GUIStyle style)
|
||||||
{
|
{
|
||||||
Vector2 size = style.CalcSize(new GUIContent(text));
|
Vector2 size = style.CalcSize(new GUIContent(text));
|
||||||
GUI.Label(new Rect(x, row.y + (row.height - 18) / 2f, size.x, 18), text, style);
|
GUI.Label(new Rect(x, row.y + (row.height - S(18)) / 2f, size.x, S(18)), text, style);
|
||||||
return size.x + 8;
|
return size.x + S(8);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Filter-Chip (an = orange umrandet), ersetzt die Unity-Häkchen.</summary>
|
/// <summary>Filter-Chip (an = orange umrandet), ersetzt die Unity-Häkchen.</summary>
|
||||||
bool Chip(bool on, string text)
|
bool Chip(bool on, string text)
|
||||||
{
|
{
|
||||||
if (GUILayout.Button(text, on ? chipOnStyle : chipOffStyle, GUILayout.Height(26), GUILayout.ExpandWidth(false))) on = !on;
|
if (GUILayout.Button(text, on ? chipOnStyle : chipOffStyle, GUILayout.Height(S(26)), GUILayout.ExpandWidth(false))) on = !on;
|
||||||
return on;
|
return on;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -646,7 +650,7 @@ namespace MSCO
|
|||||||
{
|
{
|
||||||
GUILayout.Label(caption, captionStyle);
|
GUILayout.Label(caption, captionStyle);
|
||||||
GUILayout.Label(value, valueStyle);
|
GUILayout.Label(value, valueStyle);
|
||||||
GUILayout.Space(2);
|
GUILayout.Space(S(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Ping farbig: grün gut, gelb geht so, rot schlecht.</summary>
|
/// <summary>Ping farbig: grün gut, gelb geht so, rot schlecht.</summary>
|
||||||
@@ -671,20 +675,20 @@ namespace MSCO
|
|||||||
GUILayout.Label("Version mismatch", titleStyle);
|
GUILayout.Label("Version mismatch", titleStyle);
|
||||||
GUILayout.Label("This server runs a different MSCO version than you. You can still join, but things may not " +
|
GUILayout.Label("This server runs a different MSCO version than you. You can still join, but things may not " +
|
||||||
"sync correctly (players, items, cars). For the best experience use the same version.", textStyle);
|
"sync correctly (players, items, cars). For the best experience use the same version.", textStyle);
|
||||||
GUILayout.Space(16);
|
GUILayout.Space(S(16));
|
||||||
|
|
||||||
GUILayout.Label("SERVER", captionStyle);
|
GUILayout.Label("SERVER", captionStyle);
|
||||||
GUILayout.Label(w.Name + " (" + w.Host + ":" + w.Port + ")", rowNameStyle);
|
GUILayout.Label(w.Name + " (" + w.Host + ":" + w.Port + ")", rowNameStyle);
|
||||||
GUILayout.Space(8);
|
GUILayout.Space(S(8));
|
||||||
GUILayout.Label("VERSIONS", captionStyle);
|
GUILayout.Label("VERSIONS", captionStyle);
|
||||||
GUILayout.Label("Server v" + w.ServerVersion + " - You v" + MSCO.ModVersion, rowTagStyle);
|
GUILayout.Label("Server v" + w.ServerVersion + " - You v" + MSCO.ModVersion, rowTagStyle);
|
||||||
GUILayout.Space(22);
|
GUILayout.Space(S(22));
|
||||||
|
|
||||||
GUILayout.BeginHorizontal();
|
GUILayout.BeginHorizontal();
|
||||||
if (GUILayout.Button("JOIN ANYWAY", primaryStyle, GUILayout.Height(42), GUILayout.Width(170)))
|
if (GUILayout.Button("JOIN ANYWAY", primaryStyle, GUILayout.Height(S(42)), GUILayout.Width(S(170))))
|
||||||
mp.ConfirmVersionWarning();
|
mp.ConfirmVersionWarning();
|
||||||
GUILayout.Space(10);
|
GUILayout.Space(S(10));
|
||||||
if (GUILayout.Button("CANCEL", secondaryStyle, GUILayout.Height(42), GUILayout.Width(170)))
|
if (GUILayout.Button("CANCEL", secondaryStyle, GUILayout.Height(S(42)), GUILayout.Width(S(170))))
|
||||||
mp.CancelVersionWarning();
|
mp.CancelVersionWarning();
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
}
|
}
|
||||||
@@ -694,22 +698,22 @@ namespace MSCO
|
|||||||
{
|
{
|
||||||
GUILayout.Label("Join server?", titleStyle);
|
GUILayout.Label("Join server?", titleStyle);
|
||||||
GUILayout.Label("You opened a join link from the server list.", textStyle);
|
GUILayout.Label("You opened a join link from the server list.", textStyle);
|
||||||
GUILayout.Space(18);
|
GUILayout.Space(S(18));
|
||||||
|
|
||||||
GUILayout.Label("SERVER ADDRESS", captionStyle);
|
GUILayout.Label("SERVER ADDRESS", captionStyle);
|
||||||
GUILayout.Label(mp.PendingJoinHost + ":" + mp.PendingJoinPort, rowNameStyle);
|
GUILayout.Label(mp.PendingJoinHost + ":" + mp.PendingJoinPort, rowNameStyle);
|
||||||
GUILayout.Space(24);
|
GUILayout.Space(S(24));
|
||||||
|
|
||||||
if (!mp.SteamAvailable)
|
if (!mp.SteamAvailable)
|
||||||
GUILayout.Label("Steam is required to join servers - start the game through Steam.", textStyle);
|
GUILayout.Label("Steam is required to join servers - start the game through Steam.", textStyle);
|
||||||
|
|
||||||
GUILayout.BeginHorizontal();
|
GUILayout.BeginHorizontal();
|
||||||
GUI.enabled = mp.SteamAvailable;
|
GUI.enabled = mp.SteamAvailable;
|
||||||
if (GUILayout.Button("JOIN", primaryStyle, GUILayout.Height(42), GUILayout.Width(170)))
|
if (GUILayout.Button("JOIN", primaryStyle, GUILayout.Height(S(42)), GUILayout.Width(S(170))))
|
||||||
mp.ConfirmPendingJoin();
|
mp.ConfirmPendingJoin();
|
||||||
GUI.enabled = true;
|
GUI.enabled = true;
|
||||||
GUILayout.Space(10);
|
GUILayout.Space(S(10));
|
||||||
if (GUILayout.Button("CANCEL", secondaryStyle, GUILayout.Height(42), GUILayout.Width(170)))
|
if (GUILayout.Button("CANCEL", secondaryStyle, GUILayout.Height(S(42)), GUILayout.Width(S(170))))
|
||||||
mp.CancelPendingJoin();
|
mp.CancelPendingJoin();
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
}
|
}
|
||||||
@@ -727,43 +731,43 @@ namespace MSCO
|
|||||||
{
|
{
|
||||||
if (texDim == null) texDim = Solid(new Color(0f, 0f, 0f, 0.6f));
|
if (texDim == null) texDim = Solid(new Color(0f, 0f, 0f, 0.6f));
|
||||||
if (texDanger == null) texDanger = Solid(Hex(0xe5, 0x48, 0x4d));
|
if (texDanger == null) texDanger = Solid(Hex(0xe5, 0x48, 0x4d));
|
||||||
if (promptTextStyle == null)
|
if (promptTextStyle == null || promptTextStyle.fontSize != P(15))
|
||||||
{
|
{
|
||||||
promptTextStyle = new GUIStyle(rowNameStyle);
|
promptTextStyle = new GUIStyle(rowNameStyle);
|
||||||
promptTextStyle.wordWrap = true;
|
promptTextStyle.wordWrap = true;
|
||||||
promptTextStyle.fontSize = 15;
|
promptTextStyle.fontSize = P(15);
|
||||||
}
|
}
|
||||||
GUI.DrawTexture(new Rect(0, 0, vw, vh), texDim);
|
GUI.DrawTexture(new Rect(0, 0, vw, vh), texDim);
|
||||||
|
|
||||||
var r = new Rect((vw - PromptWidth) / 2f, (vh - PromptHeight) / 2f, PromptWidth, PromptHeight);
|
var r = new Rect(Mathf.Round((vw - S(PromptWidth)) / 2f), Mathf.Round((vh - S(PromptHeight)) / 2f), S(PromptWidth), S(PromptHeight));
|
||||||
UiTheme.DrawShadow(r);
|
UiTheme.DrawShadow(r);
|
||||||
GUI.Box(r, GUIContent.none, windowBox);
|
GUI.Box(r, GUIContent.none, windowBox);
|
||||||
string title = reconnecting
|
string title = reconnecting
|
||||||
? ((mp.ReconnectMessage ?? "").StartsWith("Switching") ? "SWITCHING SERVER" : "RECONNECTING")
|
? ((mp.ReconnectMessage ?? "").StartsWith("Switching") ? "SWITCHING SERVER" : "RECONNECTING")
|
||||||
: mp.DisconnectTitle;
|
: 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, S(4)), bad ? texDanger : texAccent);
|
||||||
|
|
||||||
float x = r.x + 32, w = r.width - 64, y = r.y + 28;
|
float x = r.x + S(32), w = r.width - S(64), y = r.y + S(28);
|
||||||
GUI.Label(new Rect(x, y, w, 34), title, titleStyle);
|
GUI.Label(new Rect(x, y, w, S(34)), title, titleStyle);
|
||||||
y += 50;
|
y += S(50);
|
||||||
GUI.Label(new Rect(x, y, w, 20), "REASON", captionStyle);
|
GUI.Label(new Rect(x, y, w, S(20)), "REASON", captionStyle);
|
||||||
|
|
||||||
if (reconnecting)
|
if (reconnecting)
|
||||||
{
|
{
|
||||||
GUI.Label(new Rect(x, y + 22, w, 44), mp.ReconnectMessage ?? "", promptTextStyle);
|
GUI.Label(new Rect(x, y + S(22), w, S(44)), mp.ReconnectMessage ?? "", promptTextStyle);
|
||||||
string attempt = mp.ReconnectAttempt == 0
|
string attempt = mp.ReconnectAttempt == 0
|
||||||
? "Connecting again in a moment..."
|
? "Connecting again in a moment..."
|
||||||
: "Attempt " + mp.ReconnectAttempt + " of " + mp.ReconnectMaxAttempts +
|
: "Attempt " + mp.ReconnectAttempt + " of " + mp.ReconnectMaxAttempts +
|
||||||
(string.IsNullOrEmpty(mp.Status) ? "" : " - " + mp.Status);
|
(string.IsNullOrEmpty(mp.Status) ? "" : " - " + mp.Status);
|
||||||
GUI.Label(new Rect(x, y + 74, w, 40), attempt, textStyle);
|
GUI.Label(new Rect(x, y + S(74), w, S(40)), attempt, textStyle);
|
||||||
if (GUI.Button(new Rect(r.xMax - 32 - 170, r.yMax - 28 - 42, 170, 42), "CANCEL", secondaryStyle)) mp.CancelReconnect();
|
if (GUI.Button(new Rect(r.xMax - S(32) - S(170), r.yMax - S(28) - S(42), S(170), S(42)), "CANCEL", secondaryStyle)) mp.CancelReconnect();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GUI.Label(new Rect(x, y + 22, w, 60), mp.DisconnectNotice ?? "", promptTextStyle);
|
GUI.Label(new Rect(x, y + S(22), w, S(60)), mp.DisconnectNotice ?? "", promptTextStyle);
|
||||||
GUI.Label(new Rect(x, y + 88, w, 20), "Your own save game has been restored.", textStyle);
|
GUI.Label(new Rect(x, y + S(88), w, S(20)), "Your own save game has been restored.", textStyle);
|
||||||
if (GUI.Button(new Rect(r.xMax - 32 - 170, r.yMax - 28 - 42, 170, 42), "OK", primaryStyle)) mp.ClearDisconnectNotice();
|
if (GUI.Button(new Rect(r.xMax - S(32) - S(170), r.yMax - S(28) - S(42), S(170), S(42)), "OK", primaryStyle)) mp.ClearDisconnectNotice();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool newGameConfirm;
|
bool newGameConfirm;
|
||||||
@@ -775,38 +779,38 @@ namespace MSCO
|
|||||||
if (newGameConfirm)
|
if (newGameConfirm)
|
||||||
{
|
{
|
||||||
GUILayout.BeginVertical(rowBox);
|
GUILayout.BeginVertical(rowBox);
|
||||||
GUILayout.Space(6);
|
GUILayout.Space(S(6));
|
||||||
GUILayout.Label("START A NEW GAME?", captionStyle);
|
GUILayout.Label("START A NEW GAME?", captionStyle);
|
||||||
GUILayout.Label(saved != null
|
GUILayout.Label(saved != null
|
||||||
? "Your current save game is kept as a backup in MSCO_Saves - everyone starts in a fresh world."
|
? "Your current save game is kept as a backup in MSCO_Saves - everyone starts in a fresh world."
|
||||||
: "Everyone starts in a fresh world.", textStyle);
|
: "Everyone starts in a fresh world.", textStyle);
|
||||||
GUILayout.Space(6);
|
GUILayout.Space(S(6));
|
||||||
GUILayout.BeginHorizontal();
|
GUILayout.BeginHorizontal();
|
||||||
if (GUILayout.Button("YES, NEW GAME", dangerStyle, GUILayout.Height(38), GUILayout.Width(170)))
|
if (GUILayout.Button("YES, NEW GAME", dangerStyle, GUILayout.Height(S(38)), GUILayout.Width(S(170))))
|
||||||
{
|
{
|
||||||
newGameConfirm = false;
|
newGameConfirm = false;
|
||||||
mp.StartHostNewGame();
|
mp.StartHostNewGame();
|
||||||
}
|
}
|
||||||
GUILayout.Space(8);
|
GUILayout.Space(S(8));
|
||||||
if (GUILayout.Button("CANCEL", secondaryStyle, GUILayout.Height(38), GUILayout.Width(110))) newGameConfirm = false;
|
if (GUILayout.Button("CANCEL", secondaryStyle, GUILayout.Height(S(38)), GUILayout.Width(S(110)))) newGameConfirm = false;
|
||||||
GUILayout.FlexibleSpace();
|
GUILayout.FlexibleSpace();
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
GUILayout.Space(6);
|
GUILayout.Space(S(6));
|
||||||
GUILayout.EndVertical();
|
GUILayout.EndVertical();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GUILayout.BeginHorizontal();
|
GUILayout.BeginHorizontal();
|
||||||
GUI.enabled = saved != null;
|
GUI.enabled = saved != null;
|
||||||
GUILayout.BeginVertical(GUILayout.Width(190));
|
GUILayout.BeginVertical(GUILayout.Width(S(190)));
|
||||||
if (GUILayout.Button("CONTINUE", primaryStyle, GUILayout.Height(42), GUILayout.Width(190)))
|
if (GUILayout.Button("CONTINUE", primaryStyle, GUILayout.Height(S(42)), GUILayout.Width(S(190))))
|
||||||
mp.StartHostGame();
|
mp.StartHostGame();
|
||||||
GUILayout.Label(saved != null ? "saved " + saved.Value.ToString("dd.MM.yyyy HH:mm") : "no save game yet", captionStyle);
|
GUILayout.Label(saved != null ? "saved " + saved.Value.ToString("dd.MM.yyyy HH:mm") : "no save game yet", captionStyle);
|
||||||
GUILayout.EndVertical();
|
GUILayout.EndVertical();
|
||||||
GUI.enabled = true;
|
GUI.enabled = true;
|
||||||
GUILayout.Space(10);
|
GUILayout.Space(S(10));
|
||||||
GUILayout.BeginVertical(GUILayout.Width(190));
|
GUILayout.BeginVertical(GUILayout.Width(S(190)));
|
||||||
if (GUILayout.Button("NEW GAME", secondaryStyle, GUILayout.Height(42), GUILayout.Width(190)))
|
if (GUILayout.Button("NEW GAME", secondaryStyle, GUILayout.Height(S(42)), GUILayout.Width(S(190))))
|
||||||
{
|
{
|
||||||
if (saved != null) newGameConfirm = true;
|
if (saved != null) newGameConfirm = true;
|
||||||
else mp.StartHostNewGame();
|
else mp.StartHostNewGame();
|
||||||
@@ -825,39 +829,39 @@ namespace MSCO
|
|||||||
: mp.IsDedicated || mp.IsConnectingToServer
|
: mp.IsDedicated || mp.IsConnectingToServer
|
||||||
? "Connected to the server - the world is loading" + (string.IsNullOrEmpty(mp.Status) ? "." : ": " + mp.Status)
|
? "Connected to the server - the world is loading" + (string.IsNullOrEmpty(mp.Status) ? "." : ": " + mp.Status)
|
||||||
: "Waiting for the host to start the game.", textStyle);
|
: "Waiting for the host to start the game.", textStyle);
|
||||||
GUILayout.Space(16);
|
GUILayout.Space(S(16));
|
||||||
|
|
||||||
GUILayout.Label("PLAYERS " + mp.Players.Count + "/" + mp.SessionMaxPlayers, captionStyle);
|
GUILayout.Label("PLAYERS " + mp.Players.Count + "/" + mp.SessionMaxPlayers, captionStyle);
|
||||||
playerScroll = GUILayout.BeginScrollView(playerScroll, GUILayout.Height(ListHeight(mp.IsHost ? 330f : 170f, 120f)));
|
playerScroll = GUILayout.BeginScrollView(playerScroll, GUILayout.Height(ListHeight(mp.IsHost ? S(330f) : S(170f), S(120f))));
|
||||||
foreach (PlayerInfo p in mp.Players)
|
foreach (PlayerInfo p in mp.Players)
|
||||||
{
|
{
|
||||||
Rect row = GUILayoutUtility.GetRect(10, 32, GUILayout.ExpandWidth(true));
|
Rect row = GUILayoutUtility.GetRect(S(10), S(32), GUILayout.ExpandWidth(true));
|
||||||
GUI.Box(new Rect(row.x, row.y, row.width, row.height - 4), GUIContent.none, rowBox);
|
GUI.Box(new Rect(row.x, row.y, row.width, row.height - S(4)), GUIContent.none, rowBox);
|
||||||
// Eigener Punkt gelb, solange man noch lädt/synchronisiert; grün, wenn man wirklich im Spiel ist
|
// Eigener Punkt gelb, solange man noch lädt/synchronisiert; grün, wenn man wirklich im Spiel ist
|
||||||
GUI.DrawTexture(new Rect(row.x + 12, row.y + 11, 8, 8), p.IsLocal && !mp.IsFullyConnected ? texPending : texOnline);
|
GUI.DrawTexture(new Rect(row.x + S(12), row.y + S(11), S(8), S(8)), p.IsLocal && !mp.IsFullyConnected ? texPending : texOnline);
|
||||||
GUI.Label(new Rect(row.x + 30, row.y, row.width - 150, row.height - 2), p.Name, rowNameStyle);
|
GUI.Label(new Rect(row.x + S(30), row.y, row.width - S(150), row.height - S(2)), p.Name, rowNameStyle);
|
||||||
string tag = p.Id == NetSession.HostId ? "HOST" : "";
|
string tag = p.Id == NetSession.HostId ? "HOST" : "";
|
||||||
if (p.IsLocal) tag = tag.Length > 0 ? tag + " · YOU" : "YOU";
|
if (p.IsLocal) tag = tag.Length > 0 ? tag + " · YOU" : "YOU";
|
||||||
GUI.Label(new Rect(row.xMax - 120, row.y, 110, row.height - 2), tag, rowTagStyle);
|
GUI.Label(new Rect(row.xMax - S(120), row.y, S(110), row.height - S(2)), tag, rowTagStyle);
|
||||||
}
|
}
|
||||||
GUILayout.EndScrollView();
|
GUILayout.EndScrollView();
|
||||||
GUILayout.Space(14);
|
GUILayout.Space(S(14));
|
||||||
|
|
||||||
if (mp.IsHost)
|
if (mp.IsHost)
|
||||||
{
|
{
|
||||||
DrawHostStart(mp);
|
DrawHostStart(mp);
|
||||||
GUILayout.Space(10);
|
GUILayout.Space(S(10));
|
||||||
}
|
}
|
||||||
|
|
||||||
GUILayout.BeginHorizontal();
|
GUILayout.BeginHorizontal();
|
||||||
if (mp.IsHost)
|
if (mp.IsHost)
|
||||||
{
|
{
|
||||||
if (mp.IsSteamSession && mp.Players.Count < MultiplayerManager.MaxPlayers &&
|
if (mp.IsSteamSession && mp.Players.Count < MultiplayerManager.MaxPlayers &&
|
||||||
GUILayout.Button("INVITE FRIENDS", secondaryStyle, GUILayout.Height(42), GUILayout.Width(150)))
|
GUILayout.Button("INVITE FRIENDS", secondaryStyle, GUILayout.Height(S(42)), GUILayout.Width(S(150))))
|
||||||
mp.InviteFriends();
|
mp.InviteFriends();
|
||||||
GUILayout.Space(10);
|
GUILayout.Space(S(10));
|
||||||
}
|
}
|
||||||
if (GUILayout.Button("DISCONNECT", secondaryStyle, GUILayout.Height(42), GUILayout.Width(150)))
|
if (GUILayout.Button("DISCONNECT", secondaryStyle, GUILayout.Height(S(42)), GUILayout.Width(S(150))))
|
||||||
mp.Disconnect();
|
mp.Disconnect();
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
}
|
}
|
||||||
@@ -866,8 +870,8 @@ namespace MSCO
|
|||||||
{
|
{
|
||||||
GUI.Box(r, GUIContent.none, sidebarBox);
|
GUI.Box(r, GUIContent.none, sidebarBox);
|
||||||
Texture2D dot = mp.IsFullyConnected ? texOnline : mp.IsInSession || mp.IsReconnecting ? texPending : texMuted;
|
Texture2D dot = mp.IsFullyConnected ? texOnline : mp.IsInSession || mp.IsReconnecting ? texPending : texMuted;
|
||||||
GUI.DrawTexture(new Rect(r.x + 18, r.y + (r.height - 8) / 2f, 8, 8), dot);
|
GUI.DrawTexture(new Rect(r.x + S(18), r.y + (r.height - S(8)) / 2f, S(8), S(8)), dot);
|
||||||
GUI.Label(new Rect(r.x + 36, r.y, r.width - 72, r.height), mp.Status, statusStyle);
|
GUI.Label(new Rect(r.x + S(36), r.y, r.width - S(72), r.height), mp.Status, statusStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -875,61 +879,62 @@ namespace MSCO
|
|||||||
|
|
||||||
void EnsureStyles()
|
void EnsureStyles()
|
||||||
{
|
{
|
||||||
if (stylesReady && texBackground != null) return;
|
if (stylesReady && texBackground != null && Mathf.Abs(stylesScale - uiScale) < 0.01f) return;
|
||||||
|
stylesScale = uiScale;
|
||||||
|
|
||||||
// PlayerPrefs erst hier lesen (nicht im Konstruktor erlaubt)
|
// PlayerPrefs erst hier lesen (nicht im Konstruktor erlaubt)
|
||||||
directInput = PlayerPrefs.GetString(PrefDirect, "");
|
if (directInput == null) directInput = PlayerPrefs.GetString(PrefDirect, "");
|
||||||
|
|
||||||
texBackground = Solid(Background);
|
texBackground = Solid(Background);
|
||||||
texSidebar = Solid(Sidebar);
|
texSidebar = Solid(Sidebar);
|
||||||
texAccent = Solid(Accent);
|
texAccent = Solid(Accent);
|
||||||
texOnline = UiTheme.Rounded(Online, 4); // runde Status-Punkte
|
texOnline = UiTheme.Rounded(Online, P(4)); // runde Status-Punkte
|
||||||
texPending = UiTheme.Rounded(Pending, 4);
|
texPending = UiTheme.Rounded(Pending, P(4));
|
||||||
texMuted = UiTheme.Rounded(Muted, 4);
|
texMuted = UiTheme.Rounded(Muted, P(4));
|
||||||
texRow = Solid(Field);
|
texRow = Solid(Field);
|
||||||
// Fenster und Seitenleiste mit feinem Rand (Seitenleiste: ihr Rand trennt sie vom Inhalt)
|
// Fenster und Seitenleiste mit feinem Rand (Seitenleiste: ihr Rand trennt sie vom Inhalt)
|
||||||
windowBox = UiTheme.Card(Background, 10);
|
windowBox = UiTheme.Card(Background, P(10));
|
||||||
sidebarBox = UiTheme.Card(Sidebar, 10);
|
sidebarBox = UiTheme.Card(Sidebar, P(10));
|
||||||
rowBox = UiTheme.Panel9(Field, UiTheme.Radius);
|
rowBox = UiTheme.Panel9(Field, P(UiTheme.Radius));
|
||||||
rowHoverBox = UiTheme.Card(FieldFocus, UiTheme.Radius);
|
rowHoverBox = UiTheme.Card(FieldFocus, P(UiTheme.Radius));
|
||||||
texDivider = Solid(new Color(1f, 1f, 1f, 0.07f));
|
texDivider = Solid(new Color(1f, 1f, 1f, 0.07f));
|
||||||
texGold = Solid(Gold);
|
texGold = Solid(Gold);
|
||||||
texBarBack = Solid(new Color(1f, 1f, 1f, 0.1f));
|
texBarBack = Solid(new Color(1f, 1f, 1f, 0.1f));
|
||||||
texBarFill = Solid(Online);
|
texBarFill = Solid(Online);
|
||||||
texBarFull = Solid(UiTheme.Danger);
|
texBarFull = Solid(UiTheme.Danger);
|
||||||
accentBox = UiTheme.Panel9(Accent, 1);
|
accentBox = UiTheme.Panel9(Accent, P(1));
|
||||||
|
|
||||||
pillStyle = UiTheme.Panel9(new Color(Accent.r, Accent.g, Accent.b, 0.18f), 4);
|
pillStyle = UiTheme.Panel9(new Color(Accent.r, Accent.g, Accent.b, 0.18f), P(4));
|
||||||
pillStyle.normal.textColor = Accent;
|
pillStyle.normal.textColor = Accent;
|
||||||
pillStyle.fontSize = 10;
|
pillStyle.fontSize = P(10);
|
||||||
pillStyle.fontStyle = FontStyle.Bold;
|
pillStyle.fontStyle = FontStyle.Bold;
|
||||||
pillStyle.alignment = TextAnchor.MiddleCenter;
|
pillStyle.alignment = TextAnchor.MiddleCenter;
|
||||||
pillStyle.padding = new RectOffset(7, 7, 0, 0);
|
pillStyle.padding = new RectOffset(P(7), P(7), P(0), P(0));
|
||||||
pillStyle.wordWrap = false;
|
pillStyle.wordWrap = false;
|
||||||
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), P(4));
|
||||||
pillMutedStyle.normal.textColor = Muted;
|
pillMutedStyle.normal.textColor = Muted;
|
||||||
pillFeaturedStyle = new GUIStyle(pillStyle);
|
pillFeaturedStyle = new GUIStyle(pillStyle);
|
||||||
pillFeaturedStyle.normal.background = UiTheme.Rounded(Gold, 4);
|
pillFeaturedStyle.normal.background = UiTheme.Rounded(Gold, P(4));
|
||||||
pillFeaturedStyle.normal.textColor = Hex(0x1a, 0x12, 0x06);
|
pillFeaturedStyle.normal.textColor = Hex(0x1a, 0x12, 0x06);
|
||||||
featuredRowBox = UiTheme.Panel9(Color.Lerp(Field, Gold, 0.16f), UiTheme.Radius);
|
featuredRowBox = UiTheme.Panel9(Color.Lerp(Field, Gold, 0.16f), P(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, P(11), FontStyle.Bold);
|
||||||
chipOffStyle = Button(Field, FieldFocus, Muted, 11, FontStyle.Bold);
|
chipOffStyle = Button(Field, FieldFocus, Muted, P(11), FontStyle.Bold);
|
||||||
chipOnStyle.padding = chipOffStyle.padding = new RectOffset(12, 12, 0, 0);
|
chipOnStyle.padding = chipOffStyle.padding = new RectOffset(P(12), P(12), P(0), P(0));
|
||||||
|
|
||||||
logoStyle = Label(28, Color.white, FontStyle.Bold);
|
logoStyle = Label(P(28), Color.white, FontStyle.Bold);
|
||||||
taglineStyle = Label(10, Muted, FontStyle.Bold);
|
taglineStyle = Label(P(10), Muted, FontStyle.Bold);
|
||||||
titleStyle = Label(24, Color.white, FontStyle.Bold);
|
titleStyle = Label(P(24), Color.white, FontStyle.Bold);
|
||||||
textStyle = Label(13, Muted, FontStyle.Normal);
|
textStyle = Label(P(13), Muted, FontStyle.Normal);
|
||||||
textStyle.wordWrap = true;
|
textStyle.wordWrap = true;
|
||||||
captionStyle = Label(11, Muted, FontStyle.Bold);
|
captionStyle = Label(P(11), Muted, FontStyle.Bold);
|
||||||
captionStyle.margin.bottom = 6;
|
captionStyle.margin.bottom = P(6);
|
||||||
statusStyle = Label(12, Color.white, FontStyle.Normal);
|
statusStyle = Label(P(12), Color.white, FontStyle.Normal);
|
||||||
statusStyle.alignment = TextAnchor.MiddleLeft;
|
statusStyle.alignment = TextAnchor.MiddleLeft;
|
||||||
headerCellStyle = Label(11, Muted, FontStyle.Bold);
|
headerCellStyle = Label(P(11), Muted, FontStyle.Bold);
|
||||||
headerCellStyle.alignment = TextAnchor.MiddleLeft;
|
headerCellStyle.alignment = TextAnchor.MiddleLeft;
|
||||||
rowNameStyle = Label(14, Color.white, FontStyle.Normal);
|
rowNameStyle = Label(P(14), Color.white, FontStyle.Normal);
|
||||||
rowNameStyle.alignment = TextAnchor.MiddleLeft;
|
rowNameStyle.alignment = TextAnchor.MiddleLeft;
|
||||||
pingGoodStyle = new GUIStyle(rowNameStyle);
|
pingGoodStyle = new GUIStyle(rowNameStyle);
|
||||||
pingGoodStyle.normal.textColor = Online;
|
pingGoodStyle.normal.textColor = Online;
|
||||||
@@ -937,34 +942,34 @@ namespace MSCO
|
|||||||
pingMidStyle.normal.textColor = Pending;
|
pingMidStyle.normal.textColor = Pending;
|
||||||
pingBadStyle = new GUIStyle(rowNameStyle);
|
pingBadStyle = new GUIStyle(rowNameStyle);
|
||||||
pingBadStyle.normal.textColor = UiTheme.DangerHover;
|
pingBadStyle.normal.textColor = UiTheme.DangerHover;
|
||||||
rowTagStyle = Label(11, Accent, FontStyle.Bold);
|
rowTagStyle = Label(P(11), Accent, FontStyle.Bold);
|
||||||
rowTagStyle.alignment = TextAnchor.MiddleRight;
|
rowTagStyle.alignment = TextAnchor.MiddleRight;
|
||||||
badgeStyle = new GUIStyle(rowTagStyle);
|
badgeStyle = new GUIStyle(rowTagStyle);
|
||||||
badgeStyle.alignment = TextAnchor.MiddleLeft;
|
badgeStyle.alignment = TextAnchor.MiddleLeft;
|
||||||
badgeStyle.padding = new RectOffset(6, 6, 2, 2);
|
badgeStyle.padding = new RectOffset(P(6), P(6), P(2), P(2));
|
||||||
placeholderStyle = Label(13, Muted, FontStyle.Italic);
|
placeholderStyle = Label(P(13), Muted, FontStyle.Italic);
|
||||||
placeholderStyle.alignment = TextAnchor.MiddleLeft;
|
placeholderStyle.alignment = TextAnchor.MiddleLeft;
|
||||||
toggleStyle = new GUIStyle(GUI.skin.toggle);
|
toggleStyle = new GUIStyle(GUI.skin.toggle);
|
||||||
toggleStyle.normal.textColor = toggleStyle.onNormal.textColor = toggleStyle.hover.textColor = toggleStyle.onHover.textColor = Color.white;
|
toggleStyle.normal.textColor = toggleStyle.onNormal.textColor = toggleStyle.hover.textColor = toggleStyle.onHover.textColor = Color.white;
|
||||||
toggleStyle.fontSize = 11;
|
toggleStyle.fontSize = P(11);
|
||||||
toggleStyle.fontStyle = FontStyle.Bold;
|
toggleStyle.fontStyle = FontStyle.Bold;
|
||||||
|
|
||||||
navStyle = Button(Sidebar, Secondary, Muted, 14, FontStyle.Normal);
|
navStyle = Button(Sidebar, Secondary, Muted, P(14), FontStyle.Normal);
|
||||||
navStyle.hover.textColor = Color.white; // Hover: Text hell (vorher blieb er grau)
|
navStyle.hover.textColor = Color.white; // Hover: Text hell (vorher blieb er grau)
|
||||||
navStyle.alignment = TextAnchor.MiddleLeft;
|
navStyle.alignment = TextAnchor.MiddleLeft;
|
||||||
navStyle.padding = new RectOffset(26, 10, 0, 0);
|
navStyle.padding = new RectOffset(P(26), P(10), P(0), P(0));
|
||||||
navActiveStyle = Button(Secondary, Secondary, Color.white, 14, FontStyle.Bold);
|
navActiveStyle = Button(Secondary, Secondary, Color.white, P(14), FontStyle.Bold);
|
||||||
navActiveStyle.alignment = TextAnchor.MiddleLeft;
|
navActiveStyle.alignment = TextAnchor.MiddleLeft;
|
||||||
navActiveStyle.padding = new RectOffset(26, 10, 0, 0);
|
navActiveStyle.padding = new RectOffset(P(26), P(10), P(0), P(0));
|
||||||
|
|
||||||
primaryStyle = Button(Accent, AccentHover, Color.white, 14, FontStyle.Bold);
|
primaryStyle = Button(Accent, AccentHover, Color.white, P(14), FontStyle.Bold);
|
||||||
UiTheme.ApplyPrimaryGradient(primaryStyle);
|
UiTheme.ApplyPrimaryGradient(primaryStyle);
|
||||||
dangerStyle = Button(UiTheme.Danger, UiTheme.DangerHover, Color.white, 13, FontStyle.Bold);
|
dangerStyle = Button(UiTheme.Danger, UiTheme.DangerHover, Color.white, P(13), FontStyle.Bold);
|
||||||
secondaryStyle = Button(Secondary, SecondaryHover, Color.white, 14, FontStyle.Bold);
|
secondaryStyle = Button(Secondary, SecondaryHover, Color.white, P(14), FontStyle.Bold);
|
||||||
tabStyle = Button(Sidebar, Secondary, Muted, 11, FontStyle.Bold);
|
tabStyle = Button(Sidebar, Secondary, Muted, P(11), FontStyle.Bold);
|
||||||
tabStyle.hover.textColor = Color.white;
|
tabStyle.hover.textColor = Color.white;
|
||||||
|
|
||||||
fieldStyle = UiTheme.Field(14);
|
fieldStyle = UiTheme.Field(P(14));
|
||||||
|
|
||||||
stylesReady = true;
|
stylesReady = true;
|
||||||
}
|
}
|
||||||
|
|||||||
+83
-4
@@ -279,8 +279,84 @@ namespace MSCO
|
|||||||
/// <summary>Ping-Anzeige oben rechts (Konsole: "ping"), bleibt gespeichert.</summary>
|
/// <summary>Ping-Anzeige oben rechts (Konsole: "ping"), bleibt gespeichert.</summary>
|
||||||
public bool ShowPing
|
public bool ShowPing
|
||||||
{
|
{
|
||||||
get { return PlayerPrefs.GetInt(PrefShowPing, 0) == 1; }
|
get
|
||||||
set { PlayerPrefs.SetInt(PrefShowPing, value ? 1 : 0); }
|
{
|
||||||
|
if (showPing < 0) showPing = PlayerPrefs.GetInt(PrefShowPing, 0); // einmal lesen, nicht bei jedem Zeichnen
|
||||||
|
return showPing == 1;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
showPing = value ? 1 : 0;
|
||||||
|
PlayerPrefs.SetInt(PrefShowPing, showPing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int showPing = -1, showFps = -1;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------- FPS-Anzeige (Konsole: "fps")
|
||||||
|
const string PrefShowFps = "MSCO_ShowFps";
|
||||||
|
float fpsTimer, fpsValue = -1f, frameMsWorst;
|
||||||
|
int fpsFrames;
|
||||||
|
float frameMsWorstWindow;
|
||||||
|
|
||||||
|
/// <summary>FPS-Anzeige oben rechts, bleibt gespeichert.</summary>
|
||||||
|
public bool ShowFps
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (showFps < 0) showFps = PlayerPrefs.GetInt(PrefShowFps, 0);
|
||||||
|
return showFps == 1;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
showFps = value ? 1 : 0;
|
||||||
|
PlayerPrefs.SetInt(PrefShowFps, showFps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Bilder pro Sekunde (Mittel über eine halbe Sekunde) und längstes Bild darin (Ruckler).</summary>
|
||||||
|
public string FpsText
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (fpsValue < 0f) return "measuring...";
|
||||||
|
return Mathf.RoundToInt(fpsValue) + " FPS (" + (1000f / Mathf.Max(1f, fpsValue)).ToString("0.0") + " ms, worst " +
|
||||||
|
frameMsWorst.ToString("0") + " ms)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MeasureFps()
|
||||||
|
{
|
||||||
|
float dt = Time.unscaledDeltaTime;
|
||||||
|
fpsFrames++;
|
||||||
|
fpsTimer += dt;
|
||||||
|
frameMsWorstWindow = Mathf.Max(frameMsWorstWindow, dt * 1000f);
|
||||||
|
if (fpsTimer < 0.5f) return;
|
||||||
|
fpsValue = fpsFrames / fpsTimer;
|
||||||
|
frameMsWorst = frameMsWorstWindow;
|
||||||
|
fpsFrames = 0;
|
||||||
|
fpsTimer = 0f;
|
||||||
|
frameMsWorstWindow = 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
GUIStyle fpsStyle;
|
||||||
|
|
||||||
|
/// <summary>Oben rechts, links neben dem Ping.</summary>
|
||||||
|
void DrawFps(float rightEdge)
|
||||||
|
{
|
||||||
|
if (!ShowFps) return;
|
||||||
|
if (fpsStyle == null)
|
||||||
|
{
|
||||||
|
fpsStyle = UiTheme.Panel9(new Color(0.06f, 0.06f, 0.07f, 0.85f), 6);
|
||||||
|
fpsStyle.fontSize = 12;
|
||||||
|
fpsStyle.fontStyle = FontStyle.Bold;
|
||||||
|
fpsStyle.alignment = TextAnchor.MiddleCenter;
|
||||||
|
fpsStyle.padding = new RectOffset(10, 10, 0, 0);
|
||||||
|
}
|
||||||
|
// grün ab 50, gelb ab 30, sonst rot
|
||||||
|
fpsStyle.normal.textColor = fpsValue < 0f ? UiTheme.Muted : fpsValue >= 50f ? UiTheme.Online : fpsValue >= 30f ? UiTheme.Pending : UiTheme.Danger;
|
||||||
|
var content = new GUIContent(fpsValue < 0f ? "FPS ..." : "FPS " + Mathf.RoundToInt(fpsValue));
|
||||||
|
float width = fpsStyle.CalcSize(content).x;
|
||||||
|
GUI.Box(new Rect(rightEdge - width, 8, width, 24), content, fpsStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Text für Anzeige und Konsole.</summary>
|
/// <summary>Text für Anzeige und Konsole.</summary>
|
||||||
@@ -311,7 +387,9 @@ namespace MSCO
|
|||||||
var content = new GUIContent("PING " + PingText);
|
var content = new GUIContent("PING " + PingText);
|
||||||
float width = pingStyle.CalcSize(content).x;
|
float width = pingStyle.CalcSize(content).x;
|
||||||
GUI.Box(new Rect(Screen.width - width - 12, 8, width, 24), content, pingStyle);
|
GUI.Box(new Rect(Screen.width - width - 12, 8, width, 24), content, pingStyle);
|
||||||
|
pingWidth = width + 8;
|
||||||
}
|
}
|
||||||
|
float pingWidth; // Platz, den die Ping-Anzeige belegt (FPS steht links daneben)
|
||||||
|
|
||||||
// ---------------------------------------------------------------- Cheats (Admin-Menü)
|
// ---------------------------------------------------------------- Cheats (Admin-Menü)
|
||||||
|
|
||||||
@@ -871,6 +949,7 @@ namespace MSCO
|
|||||||
|
|
||||||
void Update()
|
void Update()
|
||||||
{
|
{
|
||||||
|
MeasureFps();
|
||||||
// Menü-Buttons des Spiels nicht durch unser Fenster hindurch auslösen (z.B. Changelog)
|
// Menü-Buttons des Spiels nicht durch unser Fenster hindurch auslösen (z.B. Changelog)
|
||||||
// Solange das Multiplayer-Fenster offen ist, reagiert das Spielmenü (CONTINUE, QUIT ...) gar nicht;
|
// Solange das Multiplayer-Fenster offen ist, reagiert das Spielmenü (CONTINUE, QUIT ...) gar nicht;
|
||||||
// erst nach MINIMIZE wieder. Über der eingeklappten Leiste ebenfalls nicht (sonst öffnet sich z.B. der Changelog).
|
// erst nach MINIMIZE wieder. Über der eingeklappten Leiste ebenfalls nicht (sonst öffnet sich z.B. der Changelog).
|
||||||
@@ -2179,7 +2258,7 @@ namespace MSCO
|
|||||||
if (MenuHelper.InMenu)
|
if (MenuHelper.InMenu)
|
||||||
{
|
{
|
||||||
lobby.Draw(this);
|
lobby.Draw(this);
|
||||||
DrawPing(); toasts.Draw();
|
pingWidth = 0f; DrawPing(); DrawFps(Screen.width - 12 - pingWidth); toasts.Draw();
|
||||||
overlays.Draw(this, false);
|
overlays.Draw(this, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2196,7 +2275,7 @@ namespace MSCO
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (session != null) DrawHud();
|
if (session != null) DrawHud();
|
||||||
DrawPing(); toasts.Draw();
|
pingWidth = 0f; DrawPing(); DrawFps(Screen.width - 12 - pingWidth); toasts.Draw();
|
||||||
overlays.Draw(this, session != null);
|
overlays.Draw(this, session != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -900,9 +900,9 @@ namespace MSCO
|
|||||||
var candidates = new List<KeyValuePair<Rigidbody, bool>>();
|
var candidates = new List<KeyValuePair<Rigidbody, bool>>();
|
||||||
var rootsByName = new Dictionary<string, List<Transform>>();
|
var rootsByName = new Dictionary<string, List<Transform>>();
|
||||||
|
|
||||||
foreach (UnityEngine.Object o in UnityEngine.Object.FindObjectsOfType(typeof(Rigidbody)))
|
foreach (Rigidbody rb in SceneCache.Rigidbodies(1f))
|
||||||
{
|
{
|
||||||
var rb = (Rigidbody)o;
|
if (rb == null) continue;
|
||||||
Transform root = rb.transform.root;
|
Transform root = rb.transform.root;
|
||||||
List<Transform> roots;
|
List<Transform> roots;
|
||||||
if (!rootsByName.TryGetValue(root.name, out roots)) rootsByName[root.name] = roots = new List<Transform>();
|
if (!rootsByName.TryGetValue(root.name, out roots)) rootsByName[root.name] = roots = new List<Transform>();
|
||||||
|
|||||||
@@ -14,6 +14,27 @@ namespace MSCO
|
|||||||
static float builtAt = -1000f;
|
static float builtAt = -1000f;
|
||||||
static int builtForLevel = -1;
|
static int builtForLevel = -1;
|
||||||
|
|
||||||
|
static Rigidbody[] bodies = new Rigidbody[0];
|
||||||
|
static float bodiesAt = -1000f;
|
||||||
|
static int bodiesForLevel = -1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Alle Rigidbodies; höchstens maxAge Sekunden alt (Objekt-Sync und Verkehr teilen sich die teure Suche).
|
||||||
|
/// Einträge können inzwischen zerstört sein (== null prüfen).
|
||||||
|
/// </summary>
|
||||||
|
public static Rigidbody[] Rigidbodies(float maxAge)
|
||||||
|
{
|
||||||
|
if (Time.realtimeSinceStartup - bodiesAt > maxAge || bodiesForLevel != Application.loadedLevel)
|
||||||
|
{
|
||||||
|
Object[] found = Object.FindObjectsOfType(typeof(Rigidbody));
|
||||||
|
bodies = new Rigidbody[found.Length];
|
||||||
|
for (int i = 0; i < found.Length; i++) bodies[i] = (Rigidbody)found[i];
|
||||||
|
bodiesAt = Time.realtimeSinceStartup;
|
||||||
|
bodiesForLevel = Application.loadedLevel;
|
||||||
|
}
|
||||||
|
return bodies;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Alle FSMs; höchstens maxAge Sekunden alt. Einträge können inzwischen zerstört sein (== null prüfen).</summary>
|
/// <summary>Alle FSMs; höchstens maxAge Sekunden alt. Einträge können inzwischen zerstört sein (== null prüfen).</summary>
|
||||||
public static PlayMakerFSM[] Fsms(float maxAge)
|
public static PlayMakerFSM[] Fsms(float maxAge)
|
||||||
{
|
{
|
||||||
|
|||||||
+3
-2
@@ -42,11 +42,12 @@ namespace MSCO
|
|||||||
foreach (Car c in cars.Values) StopFollowing(c);
|
foreach (Car c in cars.Values) StopFollowing(c);
|
||||||
cars.Clear();
|
cars.Clear();
|
||||||
seen.Clear();
|
seen.Clear();
|
||||||
nextScan = 0f;
|
nextScan = -1f; // erster Suchlauf verteilt, siehe Update
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(bool authority, float dt, Action<MsgType, byte[]> send)
|
public void Update(bool authority, float dt, Action<MsgType, byte[]> send)
|
||||||
{
|
{
|
||||||
|
if (nextScan < 0f) nextScan = Time.time + 4.5f; // nicht alle Sync-Teile im selben Frame suchen lassen
|
||||||
if (Time.time >= nextScan)
|
if (Time.time >= nextScan)
|
||||||
{
|
{
|
||||||
nextScan = Time.time + ScanInterval;
|
nextScan = Time.time + ScanInterval;
|
||||||
@@ -136,7 +137,7 @@ namespace MSCO
|
|||||||
void Scan()
|
void Scan()
|
||||||
{
|
{
|
||||||
int before = cars.Count;
|
int before = cars.Count;
|
||||||
foreach (Rigidbody rb in UnityEngine.Object.FindObjectsOfType<Rigidbody>())
|
foreach (Rigidbody rb in SceneCache.Rigidbodies(5f)) // teilt sich die Suche mit dem Objekt-Sync
|
||||||
{
|
{
|
||||||
if (rb == null || !seen.Add(rb)) continue;
|
if (rb == null || !seen.Add(rb)) continue;
|
||||||
if (Array.IndexOf(Roots, rb.transform.root.name) < 0) continue;
|
if (Array.IndexOf(Roots, rb.transform.root.name) < 0) continue;
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@ namespace MSCO
|
|||||||
string n = name.ToLower();
|
string n = name.ToLower();
|
||||||
return n.Contains("needle") || n.Contains("steeringwheel");
|
return n.Contains("needle") || n.Contains("steeringwheel");
|
||||||
}
|
}
|
||||||
const float CacheRefresh = 5f; // Teile können an-/abgebaut werden
|
const float CacheRefresh = 15f; // Teile können an-/abgebaut werden (Nachschlagen ist teuer: ganzes Fahrzeug)
|
||||||
const float ApplyTimeout = 2f; // ohne neue Daten nichts mehr erzwingen
|
const float ApplyTimeout = 2f; // ohne neue Daten nichts mehr erzwingen
|
||||||
|
|
||||||
struct AudioState
|
struct AudioState
|
||||||
|
|||||||
+2
-1
@@ -58,11 +58,12 @@ namespace MSCO
|
|||||||
vars.Clear();
|
vars.Clear();
|
||||||
pending.Clear();
|
pending.Clear();
|
||||||
scanned.Clear();
|
scanned.Clear();
|
||||||
nextScan = 0f;
|
nextScan = -1f; // erster Suchlauf verteilt, siehe Update
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(ObjectSync objects, int localId, Action<MsgType, byte[]> send)
|
public void Update(ObjectSync objects, int localId, Action<MsgType, byte[]> send)
|
||||||
{
|
{
|
||||||
|
if (nextScan < 0f) nextScan = Time.time + 3.1f; // nicht alle Sync-Teile im selben Frame suchen lassen
|
||||||
if (Time.time >= nextScan)
|
if (Time.time >= nextScan)
|
||||||
{
|
{
|
||||||
nextScan = Time.time + ScanInterval;
|
nextScan = Time.time + ScanInterval;
|
||||||
|
|||||||
+2
-1
@@ -49,11 +49,12 @@ namespace MSCO
|
|||||||
{
|
{
|
||||||
vars.Clear();
|
vars.Clear();
|
||||||
scanned.Clear();
|
scanned.Clear();
|
||||||
nextScan = 0f;
|
nextScan = -1f; // erster Suchlauf verteilt, siehe Update
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(Action<MsgType, byte[]> send)
|
public void Update(Action<MsgType, byte[]> send)
|
||||||
{
|
{
|
||||||
|
if (nextScan < 0f) nextScan = Time.time + 3.8f; // nicht alle Sync-Teile im selben Frame suchen lassen
|
||||||
if (Time.time >= nextScan)
|
if (Time.time >= nextScan)
|
||||||
{
|
{
|
||||||
nextScan = Time.time + ScanInterval;
|
nextScan = Time.time + ScanInterval;
|
||||||
|
|||||||
Reference in New Issue
Block a user