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;
}