diff --git a/FsmSync.cs b/FsmSync.cs index d285379..7c8ed72 100644 --- a/FsmSync.cs +++ b/FsmSync.cs @@ -167,18 +167,25 @@ namespace MSCO } } + static Camera aimCamera; + static int aimCameraFrame = -1; + static bool IsAimedAt(Fsm fsm, out float aimDistance) { aimDistance = float.MaxValue; GameObject go = fsm.GameObject; - Camera cam = Camera.main; + // Läuft im Klick-Fenster für jede FSM, die den Zustand wechselt: Kamera nur einmal pro Bild suchen + if (aimCameraFrame != Time.frameCount) { aimCameraFrame = Time.frameCount; aimCamera = Camera.main; } + Camera cam = aimCamera; if (go == null || cam == null) return false; + + // Erst der billige Abstand, dann die Namen (jeder .name-Zugriff erzeugt einen neuen String) + Transform camT = cam.transform; + Vector3 toObject = go.transform.position - camT.position; + if (toObject.sqrMagnitude > ClickRange * ClickRange || Vector3.Dot(toObject, camT.forward) < 0f) return false; string root = go.transform.root.name; if (root == "PLAYER" || root.StartsWith("MSCO_")) return false; - - Vector3 toObject = go.transform.position - cam.transform.position; - if (toObject.magnitude > ClickRange || Vector3.Dot(toObject, cam.transform.forward) < 0f) return false; - aimDistance = Vector3.Cross(cam.transform.forward, toObject).magnitude; // Abstand zur Blickachse + aimDistance = Vector3.Cross(camT.forward, toObject).magnitude; // Abstand zur Blickachse return true; } diff --git a/MultiplayerManager.cs b/MultiplayerManager.cs index 3f394e1..3ad9523 100644 --- a/MultiplayerManager.cs +++ b/MultiplayerManager.cs @@ -367,11 +367,23 @@ namespace MSCO } // 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); + int shown = fpsValue < 0f ? -1 : Mathf.RoundToInt(fpsValue); + if (shown != fpsShown || fpsContent.text == null) + { + fpsShown = shown; + fpsContent.text = shown < 0 ? "FPS ..." : "FPS " + shown; + fpsWidth = fpsStyle.CalcSize(fpsContent).x; + } + GUI.Box(new Rect(rightEdge - fpsWidth, 8, fpsWidth, 24), fpsContent, fpsStyle); } + // Anzeige-Texte zwischengespeichert (nur bei Änderung neu gebaut, siehe DrawFps/DrawPing) + readonly GUIContent fpsContent = new GUIContent(), pingContent = new GUIContent(); + int fpsShown = int.MinValue; + float fpsWidth; + string pingShown; + float pingTextWidth; + /// Text für Anzeige und Konsole. public string PingText { @@ -379,7 +391,10 @@ namespace MSCO { if (session == null) return "not connected"; if (session.IsHost) return "you are the host"; - return pingMs < 0f ? "measuring..." : Mathf.RoundToInt(pingMs) + " ms"; + if (pingMs < 0f) return "measuring..."; + int ms = Mathf.RoundToInt(pingMs); + if (ms != pingTextMs || pingTextCache == null) { pingTextMs = ms; pingTextCache = ms + " ms"; } + return pingTextCache; } } @@ -397,12 +412,20 @@ namespace MSCO // Farbe nach Qualität: grün < 80 ms, gelb < 150 ms, sonst rot Color color = pingMs < 0f ? UiTheme.Muted : pingMs < 80f ? UiTheme.Online : pingMs < 150f ? UiTheme.Pending : UiTheme.Danger; pingStyle.normal.textColor = color; - var content = new GUIContent("PING " + PingText); - float width = pingStyle.CalcSize(content).x; - GUI.Box(new Rect(Screen.width - width - 12, 8, width, 24), content, pingStyle); + string ping = PingText; // ändert sich nur, wenn eine neue Messung da ist + if (ping != pingShown) + { + pingShown = ping; + pingContent.text = "PING " + ping; + pingTextWidth = pingStyle.CalcSize(pingContent).x; + } + float width = pingTextWidth; + GUI.Box(new Rect(Screen.width - width - 12, 8, width, 24), pingContent, pingStyle); pingWidth = width + 8; } float pingWidth; // Platz, den die Ping-Anzeige belegt (FPS steht links daneben) + int pingTextMs = int.MinValue; + string pingTextCache; // ---------------------------------------------------------------- Cheats (Admin-Menü) @@ -2170,12 +2193,12 @@ namespace MSCO PartStart(); try { objects.Update(localPlayer, Time.deltaTime); } catch (System.Exception e) { ReportError("object sync", e); } - PartStart(); PartEnd("object sync"); + PartStart(); try { vehicleFx.Update(objects, SendGame, Time.deltaTime, IsWorldAuthority); } catch (System.Exception e) { ReportError("vehicle lights/sound", e); } - PartStart(); PartEnd("vehicle lights/sound"); + PartStart(); try { worldSync.Update(IsWorldAuthority, SendGame, Time.unscaledDeltaTime); } catch (System.Exception e) { ReportError("time/weather sync", e); } PartEnd("time/weather sync"); @@ -2260,6 +2283,7 @@ namespace MSCO } // Abgefangene Schraub-/Montage-Aktionen verschicken + PartStart(); try { FsmSync.Enabled = ready; diff --git a/ObjectSync.cs b/ObjectSync.cs index 8774a01..ecf10da 100644 --- a/ObjectSync.cs +++ b/ObjectSync.cs @@ -811,15 +811,23 @@ namespace MSCO return attached; } - static bool IsAttached(SyncedBody b) + bool IsAttached(SyncedBody b) { if (b.IsVehicle || b.Rb == null) return false; // Unter einem anderen Rigidbody (z.B. am Auto eingehängt) for (Transform p = b.Rb.transform.parent; p != null; p = p.parent) if (p.GetComponent() != null) return true; - // Per Gelenk mit etwas verbunden, das nicht der Spieler ist (die Hand hält Items nicht über Gelenke fest) + // Per Gelenk mit etwas verbunden, das nicht der Spieler ist (die Hand hält Items nicht über Gelenke fest). + // Läuft alle 0,5 s für jedes Teil: erst billig prüfen, ob es überhaupt ein Gelenk hat (GetComponents legt + // jedes Mal ein neues Array an - die allermeisten Teile haben keins). + if (b.Rb.GetComponent() == null) return false; + Transform playerRoot = Head != null ? Head.root : null; foreach (Joint j in b.Rb.GetComponents()) - if (j != null && j.connectedBody != null && j.connectedBody.transform.root.name != "PLAYER") return true; + { + if (j == null || j.connectedBody == null) continue; + Transform root = j.connectedBody.transform.root; + if (playerRoot != null ? root != playerRoot : root.name != "PLAYER") return true; + } return false; } diff --git a/Overlays.cs b/Overlays.cs index 29e6705..f851fa8 100644 --- a/Overlays.cs +++ b/Overlays.cs @@ -30,8 +30,13 @@ namespace MSCO public string Name, Text; public bool System; public float Time; + // "Name:" und seine Breite - einmal berechnet statt bei jedem OnGUI-Durchlauf (2-3x pro Bild) + public string NameLabel; + public float NameWidth = -1f; } + readonly List visibleChat = new List(); + // Konsole public bool ConsoleOpen { get; private set; } readonly List consoleLines = new List(); @@ -211,7 +216,8 @@ namespace MSCO int maxLines = ChatOpen ? 12 : 6; // Sichtbare Zeilen: offen = die letzten, geschlossen = nur neue (blenden aus) - var visible = new List(); + var visible = visibleChat; + visible.Clear(); for (int i = chat.Count - 1; i >= 0 && visible.Count < maxLines; i--) if (ChatOpen || now - chat[i].Time < ChatFadeSeconds) visible.Insert(0, chat[i]); @@ -233,9 +239,14 @@ namespace MSCO } else { - Vector2 size = chatName.CalcSize(new GUIContent(line.Name + ":")); - GUI.Label(new Rect(rect.x + 12, y, size.x, lineHeight), line.Name + ":", chatName); - GUI.Label(new Rect(rect.x + 16 + size.x, y, width - 28 - size.x, lineHeight), line.Text, chatText); + if (line.NameWidth < 0f) + { + line.NameLabel = line.Name + ":"; + line.NameWidth = chatName.CalcSize(new GUIContent(line.NameLabel)).x; + } + float nameWidth = line.NameWidth; + GUI.Label(new Rect(rect.x + 12, y, nameWidth, lineHeight), line.NameLabel, chatName); + GUI.Label(new Rect(rect.x + 16 + nameWidth, y, width - 28 - nameWidth, lineHeight), line.Text, chatText); } y += lineHeight; }