MSCO 2.9.1: fixes without MSCLoader, admin teleport, MSCO branding
- Own JSON reader (MiniJson) instead of Newtonsoft.Json - the server browser failed with "Could not load System.Runtime.Serialization" once MSCLoader was gone - Mouse cursor visible in admin menu/chat/console (PlayerInMenu) - Intro "Press any key" screen replaced by an MSCO loading screen; hook PlayMakerFSM.Awake too - Join links while the game runs: picked up from MSCO\join.txt (written by the launcher) - Admin menu: TELEPORT tab (home, shop, repair shop, inspection, villages, events, Satsuma) - Window title/icon "MSCO - My Summer Car Online", MSCO logo in the main menu - In-game UI restyled like the keymaster website (rounded cards, pills, glow, slim scrollbars) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+82
-31
@@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MSCO
|
||||
@@ -33,10 +33,10 @@ namespace MSCO
|
||||
float ListHeight(float reserved, float min) { return Mathf.Max(min, contentHeight - reserved); }
|
||||
|
||||
|
||||
static readonly Color Background = Hex(0x17, 0x17, 0x1b);
|
||||
static readonly Color Sidebar = Hex(0x0f, 0x0f, 0x12);
|
||||
static readonly Color Field = Hex(0x24, 0x24, 0x2a);
|
||||
static readonly Color FieldFocus = Hex(0x2e, 0x2e, 0x36);
|
||||
static readonly Color Background = Hex(0x11, 0x11, 0x14);
|
||||
static readonly Color Sidebar = Hex(0x0c, 0x0c, 0x0f);
|
||||
static readonly Color Field = Hex(0x1b, 0x1b, 0x20);
|
||||
static readonly Color FieldFocus = Hex(0x24, 0x24, 0x2a);
|
||||
static readonly Color Accent = Hex(0xf2, 0x6b, 0x1d);
|
||||
static readonly Color AccentHover = Hex(0xff, 0x82, 0x3a);
|
||||
static readonly Color Secondary = Hex(0x2c, 0x2c, 0x33);
|
||||
@@ -65,7 +65,8 @@ namespace MSCO
|
||||
|
||||
bool stylesReady;
|
||||
Texture2D texBackground, texSidebar, texAccent, texOnline, texPending, texMuted, texRow;
|
||||
Texture2D texDivider, texGold, texBarBack, texBarFill, texBarFull;
|
||||
Texture2D texDivider, texGold, texBarBack, texBarFill, texBarFull, texGlow;
|
||||
GUIStyle scrollbarStyle, scrollThumbStyle;
|
||||
GUIStyle rowHoverBox, pingGoodStyle, pingMidStyle, pingBadStyle;
|
||||
List<ServerListEntry> shownAll, shownServers; // Stand des letzten Layout-Durchgangs
|
||||
string layoutError;
|
||||
@@ -123,6 +124,8 @@ namespace MSCO
|
||||
if (mp.IsReconnecting) { DrawPrompt(mp, true); return; }
|
||||
var window = new Rect(0, 0, vw, vh);
|
||||
GUI.Box(window, GUIContent.none, windowBox);
|
||||
float glowWidth = Mathf.Min(vw * 0.9f, S(1300));
|
||||
GUI.DrawTexture(new Rect(S(SidebarWidth) + (vw - S(SidebarWidth) - glowWidth) / 2f, -S(60), glowWidth, S(420)), texGlow);
|
||||
|
||||
DrawSidebar(new Rect(0, 0, S(SidebarWidth), vh - S(StatusHeight)));
|
||||
|
||||
@@ -131,6 +134,9 @@ namespace MSCO
|
||||
float width = Mathf.Min(S(MaxContentWidth), free - S(96f));
|
||||
var content = new Rect(S(SidebarWidth) + Mathf.Round((free - width) / 2f), S(40f), width, vh - S(StatusHeight) - S(72f));
|
||||
contentHeight = content.height;
|
||||
GUIStyle oldBar = GUI.skin.verticalScrollbar, oldThumb = GUI.skin.verticalScrollbarThumb;
|
||||
GUI.skin.verticalScrollbar = scrollbarStyle;
|
||||
GUI.skin.verticalScrollbarThumb = scrollThumbStyle;
|
||||
GUILayout.BeginArea(content);
|
||||
if (versionWarning) DrawVersionWarning(mp);
|
||||
else if (pendingJoin) DrawJoinConfirm(mp);
|
||||
@@ -139,6 +145,8 @@ namespace MSCO
|
||||
else if (page == Page.Favorites) DrawFavorites(mp);
|
||||
else DrawServerBrowser(mp);
|
||||
GUILayout.EndArea();
|
||||
GUI.skin.verticalScrollbar = oldBar;
|
||||
GUI.skin.verticalScrollbarThumb = oldThumb;
|
||||
|
||||
DrawStatusBar(mp, new Rect(0, vh - S(StatusHeight), vw, S(StatusHeight)));
|
||||
|
||||
@@ -206,8 +214,10 @@ namespace MSCO
|
||||
|
||||
bool NavButton(Rect r, string text, bool active)
|
||||
{
|
||||
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);
|
||||
var item = new Rect(r.x + S(12), r.y, r.width - S(24), r.height);
|
||||
bool clicked = GUI.Button(item, text, active ? navActiveStyle : navStyle);
|
||||
if (active) GUI.Box(new Rect(item.x + S(8), item.y + S(11), S(3), item.height - S(22)), GUIContent.none, accentBox); // Akzentbalken
|
||||
return clicked;
|
||||
}
|
||||
|
||||
void DrawP2P(MultiplayerManager mp)
|
||||
@@ -291,8 +301,9 @@ namespace MSCO
|
||||
string shownError = Event.current.type == EventType.Layout ? (layoutError = browser.Error) : layoutError;
|
||||
|
||||
// Tabellenkopf
|
||||
GUILayout.Space(S(6));
|
||||
Rect header = GUILayoutUtility.GetRect(S(10), S(26), GUILayout.ExpandWidth(true));
|
||||
GUI.Box(header, GUIContent.none, rowBox);
|
||||
GUI.DrawTexture(new Rect(header.x, header.yMax - S(1), header.width, S(1)), texDivider);
|
||||
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, S(70), header.height), "PLAYERS", headerCellStyle);
|
||||
GUI.Label(new Rect(header.x + header.width * 0.62f, header.y, S(70), header.height), "TYPE", headerCellStyle);
|
||||
@@ -933,8 +944,16 @@ namespace MSCO
|
||||
// Fenster und Seitenleiste mit feinem Rand (Seitenleiste: ihr Rand trennt sie vom Inhalt)
|
||||
windowBox = UiTheme.Card(Background, P(10));
|
||||
sidebarBox = UiTheme.Card(Sidebar, P(10));
|
||||
rowBox = UiTheme.Panel9(Field, P(UiTheme.Radius));
|
||||
rowHoverBox = UiTheme.Card(FieldFocus, P(UiTheme.Radius));
|
||||
rowBox = UiTheme.Card(Field, P(10));
|
||||
rowHoverBox = new GUIStyle(rowBox);
|
||||
rowHoverBox.normal.background = UiTheme.RoundedEx(FieldFocus, FieldFocus, new Color(Accent.r, Accent.g, Accent.b, 0.45f), true, P(10), P(10) * 2 + 4);
|
||||
texGlow = Glow(new Color(Accent.r, Accent.g, Accent.b, 0.16f));
|
||||
scrollbarStyle = new GUIStyle();
|
||||
scrollbarStyle.fixedWidth = S(8);
|
||||
scrollbarStyle.margin = new RectOffset(P(6), 0, 0, 0);
|
||||
scrollThumbStyle = UiTheme.Panel9(new Color(1f, 1f, 1f, 0.14f), P(3));
|
||||
scrollThumbStyle.fixedWidth = S(6);
|
||||
scrollThumbStyle.hover.background = UiTheme.Rounded(new Color(1f, 1f, 1f, 0.24f), P(3));
|
||||
texDivider = Solid(new Color(1f, 1f, 1f, 0.07f));
|
||||
texGold = Solid(Gold);
|
||||
texBarBack = Solid(new Color(1f, 1f, 1f, 0.1f));
|
||||
@@ -955,10 +974,11 @@ namespace MSCO
|
||||
pillFeaturedStyle = new GUIStyle(pillStyle);
|
||||
pillFeaturedStyle.normal.background = UiTheme.Rounded(Gold, P(4));
|
||||
pillFeaturedStyle.normal.textColor = Hex(0x1a, 0x12, 0x06);
|
||||
featuredRowBox = UiTheme.Panel9(Color.Lerp(Field, Gold, 0.16f), P(UiTheme.Radius));
|
||||
featuredRowBox = UiTheme.Card(Color.Lerp(Field, Gold, 0.14f), P(10));
|
||||
|
||||
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, P(11), FontStyle.Bold);
|
||||
chipOnStyle = Button(new Color(Accent.r, Accent.g, Accent.b, 0.2f), new Color(Accent.r, Accent.g, Accent.b, 0.3f), AccentHover, P(11), FontStyle.Bold, P(11), new Color(Accent.r, Accent.g, Accent.b, 0.55f));
|
||||
chipOffStyle = Button(Field, FieldFocus, Muted, P(11), FontStyle.Bold, P(11), UiTheme.Border);
|
||||
chipOffStyle.hover.textColor = Color.white;
|
||||
chipOnStyle.padding = chipOffStyle.padding = new RectOffset(P(12), P(12), P(0), P(0));
|
||||
|
||||
logoStyle = Label(P(28), Color.white, FontStyle.Bold);
|
||||
@@ -992,22 +1012,28 @@ namespace MSCO
|
||||
toggleStyle.fontSize = P(11);
|
||||
toggleStyle.fontStyle = FontStyle.Bold;
|
||||
|
||||
navStyle = Button(Sidebar, Secondary, Muted, P(14), FontStyle.Normal);
|
||||
navStyle = Button(Sidebar, new Color(1f, 1f, 1f, 0.05f), Muted, P(14), FontStyle.Normal, P(10));
|
||||
navStyle.hover.textColor = Color.white; // Hover: Text hell (vorher blieb er grau)
|
||||
navStyle.alignment = TextAnchor.MiddleLeft;
|
||||
navStyle.padding = new RectOffset(P(26), P(10), P(0), P(0));
|
||||
navActiveStyle = Button(Secondary, Secondary, Color.white, P(14), FontStyle.Bold);
|
||||
navStyle.padding = new RectOffset(P(22), P(10), P(0), P(0));
|
||||
navActiveStyle = Button(Color.Lerp(Sidebar, Accent, 0.12f), Color.Lerp(Sidebar, Accent, 0.16f), Color.white, P(14), FontStyle.Bold, P(10), new Color(Accent.r, Accent.g, Accent.b, 0.25f));
|
||||
navActiveStyle.alignment = TextAnchor.MiddleLeft;
|
||||
navActiveStyle.padding = new RectOffset(P(26), P(10), P(0), P(0));
|
||||
navActiveStyle.padding = new RectOffset(P(22), P(10), P(0), P(0));
|
||||
|
||||
primaryStyle = Button(Accent, AccentHover, Color.white, P(14), FontStyle.Bold);
|
||||
UiTheme.ApplyPrimaryGradient(primaryStyle);
|
||||
dangerStyle = Button(UiTheme.Danger, UiTheme.DangerHover, Color.white, P(13), FontStyle.Bold);
|
||||
secondaryStyle = Button(Secondary, SecondaryHover, Color.white, P(14), FontStyle.Bold);
|
||||
tabStyle = Button(Sidebar, Secondary, Muted, P(11), FontStyle.Bold);
|
||||
primaryStyle = Button(Accent, AccentHover, Color.white, P(14), FontStyle.Bold, P(10));
|
||||
primaryStyle.normal.background = primaryStyle.focused.background = UiTheme.RoundedEx(AccentHover, Accent, Color.clear, false, P(10));
|
||||
primaryStyle.hover.background = primaryStyle.active.background = primaryStyle.onNormal.background =
|
||||
UiTheme.RoundedEx(Color.Lerp(AccentHover, Color.white, 0.12f), AccentHover, Color.clear, false, P(10));
|
||||
dangerStyle = Button(UiTheme.Danger, UiTheme.DangerHover, Color.white, P(13), FontStyle.Bold, P(10));
|
||||
secondaryStyle = Button(Hex(0x22, 0x22, 0x28), Hex(0x2a, 0x2a, 0x31), Color.white, P(14), FontStyle.Bold, P(10), UiTheme.Border);
|
||||
tabStyle = Button(Hex(0x1b, 0x1b, 0x20), Hex(0x24, 0x24, 0x2a), Muted, P(11), FontStyle.Bold, P(10), UiTheme.Border);
|
||||
tabStyle.hover.textColor = Color.white;
|
||||
|
||||
fieldStyle = UiTheme.Field(P(14));
|
||||
fieldStyle.normal.background = UiTheme.RoundedEx(Hex(0x16, 0x16, 0x1a), Hex(0x16, 0x16, 0x1a), UiTheme.Border, true, P(10), P(10) * 2 + 4);
|
||||
fieldStyle.hover.background = UiTheme.RoundedEx(Hex(0x19, 0x19, 0x1e), Hex(0x19, 0x19, 0x1e), new Color(1f, 1f, 1f, 0.14f), true, P(10), P(10) * 2 + 4);
|
||||
fieldStyle.focused.background = UiTheme.RoundedEx(Hex(0x19, 0x19, 0x1e), Hex(0x19, 0x19, 0x1e), Accent, true, P(10), P(10) * 2 + 4);
|
||||
fieldStyle.border = new RectOffset(P(10) + 2, P(10) + 2, P(10) + 2, P(10) + 2);
|
||||
|
||||
stylesReady = true;
|
||||
}
|
||||
@@ -1021,21 +1047,46 @@ namespace MSCO
|
||||
return s;
|
||||
}
|
||||
|
||||
static GUIStyle Button(Color normal, Color hover, Color text, int size, FontStyle font)
|
||||
/// <summary>Knopf mit runden Ecken (9-Slice, siehe UiTheme), optional mit feinem Rand wie .btn auf der Website.</summary>
|
||||
static GUIStyle Button(Color normal, Color hover, Color text, int size, FontStyle font, int radius = UiTheme.Radius, Color border = default(Color))
|
||||
{
|
||||
var s = new GUIStyle(GUI.skin.button);
|
||||
// abgerundete Ecken (9-Slice), siehe UiTheme
|
||||
s.normal.background = UiTheme.Rounded(normal);
|
||||
s.hover.background = UiTheme.Rounded(hover);
|
||||
s.active.background = UiTheme.Rounded(hover);
|
||||
s.focused.background = UiTheme.Rounded(normal);
|
||||
s.normal.textColor = s.hover.textColor = s.active.textColor = s.focused.textColor = text;
|
||||
s.border = new RectOffset(UiTheme.Radius + 2, UiTheme.Radius + 2, UiTheme.Radius + 2, UiTheme.Radius + 2);
|
||||
bool withBorder = border.a > 0f;
|
||||
int h = radius * 2 + 4;
|
||||
Texture2D n = UiTheme.RoundedEx(normal, normal, border, withBorder, radius, h);
|
||||
Texture2D o = UiTheme.RoundedEx(hover, hover, withBorder ? new Color(border.r, border.g, border.b, Mathf.Min(1f, border.a * 1.8f)) : border, withBorder, radius, h);
|
||||
s.normal.background = n;
|
||||
s.focused.background = n;
|
||||
s.hover.background = o;
|
||||
s.active.background = o;
|
||||
s.onNormal.background = o;
|
||||
s.normal.textColor = s.hover.textColor = s.active.textColor = s.focused.textColor = s.onNormal.textColor = text;
|
||||
s.border = new RectOffset(radius + 2, radius + 2, radius + 2, radius + 2);
|
||||
s.fontSize = size;
|
||||
s.fontStyle = font;
|
||||
return s;
|
||||
}
|
||||
|
||||
/// <summary>Weicher runder Schein (Mitte deckend, nach außen durchsichtig) - für den orangen Schimmer oben.</summary>
|
||||
static Texture2D Glow(Color color)
|
||||
{
|
||||
const int w = 128, h = 64;
|
||||
var tex = new Texture2D(w, h, TextureFormat.ARGB32, false);
|
||||
tex.wrapMode = TextureWrapMode.Clamp;
|
||||
tex.filterMode = FilterMode.Bilinear;
|
||||
for (int y = 0; y < h; y++)
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
float dx = (x + 0.5f) / w * 2f - 1f, dy = (y + 0.5f) / h * 2f - 1f;
|
||||
float d = Mathf.Clamp01(Mathf.Sqrt(dx * dx + dy * dy));
|
||||
float a = 1f - d;
|
||||
tex.SetPixel(x, y, new Color(color.r, color.g, color.b, color.a * a * a));
|
||||
}
|
||||
tex.Apply();
|
||||
tex.hideFlags = HideFlags.HideAndDontSave;
|
||||
return tex;
|
||||
}
|
||||
|
||||
static Texture2D Solid(Color color)
|
||||
{
|
||||
var tex = new Texture2D(1, 1);
|
||||
|
||||
Reference in New Issue
Block a user