Less garbage, fewer GC hitches: no Joint array per part every 0.5 s, cheap aim check after clicks, cached FPS/ping/chat labels; perf report measures object sync, vehicle fx and part/bolt sync correctly
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
fe08fa5213
commit
d567d5992a
+12
-5
@@ -167,18 +167,25 @@ namespace MSCO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Camera aimCamera;
|
||||||
|
static int aimCameraFrame = -1;
|
||||||
|
|
||||||
static bool IsAimedAt(Fsm fsm, out float aimDistance)
|
static bool IsAimedAt(Fsm fsm, out float aimDistance)
|
||||||
{
|
{
|
||||||
aimDistance = float.MaxValue;
|
aimDistance = float.MaxValue;
|
||||||
GameObject go = fsm.GameObject;
|
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;
|
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;
|
string root = go.transform.root.name;
|
||||||
if (root == "PLAYER" || root.StartsWith("MSCO_")) return false;
|
if (root == "PLAYER" || root.StartsWith("MSCO_")) return false;
|
||||||
|
aimDistance = Vector3.Cross(camT.forward, toObject).magnitude; // Abstand zur Blickachse
|
||||||
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
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+33
-9
@@ -367,10 +367,22 @@ namespace MSCO
|
|||||||
}
|
}
|
||||||
// grün ab 50, gelb ab 30, sonst rot
|
// 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;
|
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));
|
int shown = fpsValue < 0f ? -1 : Mathf.RoundToInt(fpsValue);
|
||||||
float width = fpsStyle.CalcSize(content).x;
|
if (shown != fpsShown || fpsContent.text == null)
|
||||||
GUI.Box(new Rect(rightEdge - width, 8, width, 24), content, fpsStyle);
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
/// <summary>Text für Anzeige und Konsole.</summary>
|
/// <summary>Text für Anzeige und Konsole.</summary>
|
||||||
public string PingText
|
public string PingText
|
||||||
@@ -379,7 +391,10 @@ namespace MSCO
|
|||||||
{
|
{
|
||||||
if (session == null) return "not connected";
|
if (session == null) return "not connected";
|
||||||
if (session.IsHost) return "you are the host";
|
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
|
// 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;
|
Color color = pingMs < 0f ? UiTheme.Muted : pingMs < 80f ? UiTheme.Online : pingMs < 150f ? UiTheme.Pending : UiTheme.Danger;
|
||||||
pingStyle.normal.textColor = color;
|
pingStyle.normal.textColor = color;
|
||||||
var content = new GUIContent("PING " + PingText);
|
string ping = PingText; // ändert sich nur, wenn eine neue Messung da ist
|
||||||
float width = pingStyle.CalcSize(content).x;
|
if (ping != pingShown)
|
||||||
GUI.Box(new Rect(Screen.width - width - 12, 8, width, 24), content, pingStyle);
|
{
|
||||||
|
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;
|
pingWidth = width + 8;
|
||||||
}
|
}
|
||||||
float pingWidth; // Platz, den die Ping-Anzeige belegt (FPS steht links daneben)
|
float pingWidth; // Platz, den die Ping-Anzeige belegt (FPS steht links daneben)
|
||||||
|
int pingTextMs = int.MinValue;
|
||||||
|
string pingTextCache;
|
||||||
|
|
||||||
// ---------------------------------------------------------------- Cheats (Admin-Menü)
|
// ---------------------------------------------------------------- Cheats (Admin-Menü)
|
||||||
|
|
||||||
@@ -2170,12 +2193,12 @@ namespace MSCO
|
|||||||
PartStart();
|
PartStart();
|
||||||
try { objects.Update(localPlayer, Time.deltaTime); }
|
try { objects.Update(localPlayer, Time.deltaTime); }
|
||||||
catch (System.Exception e) { ReportError("object sync", e); }
|
catch (System.Exception e) { ReportError("object sync", e); }
|
||||||
PartStart();
|
|
||||||
PartEnd("object sync");
|
PartEnd("object sync");
|
||||||
|
PartStart();
|
||||||
try { vehicleFx.Update(objects, SendGame, Time.deltaTime, IsWorldAuthority); }
|
try { vehicleFx.Update(objects, SendGame, Time.deltaTime, IsWorldAuthority); }
|
||||||
catch (System.Exception e) { ReportError("vehicle lights/sound", e); }
|
catch (System.Exception e) { ReportError("vehicle lights/sound", e); }
|
||||||
PartStart();
|
|
||||||
PartEnd("vehicle lights/sound");
|
PartEnd("vehicle lights/sound");
|
||||||
|
PartStart();
|
||||||
try { worldSync.Update(IsWorldAuthority, SendGame, Time.unscaledDeltaTime); }
|
try { worldSync.Update(IsWorldAuthority, SendGame, Time.unscaledDeltaTime); }
|
||||||
catch (System.Exception e) { ReportError("time/weather sync", e); }
|
catch (System.Exception e) { ReportError("time/weather sync", e); }
|
||||||
PartEnd("time/weather sync");
|
PartEnd("time/weather sync");
|
||||||
@@ -2260,6 +2283,7 @@ namespace MSCO
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Abgefangene Schraub-/Montage-Aktionen verschicken
|
// Abgefangene Schraub-/Montage-Aktionen verschicken
|
||||||
|
PartStart();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
FsmSync.Enabled = ready;
|
FsmSync.Enabled = ready;
|
||||||
|
|||||||
+11
-3
@@ -811,15 +811,23 @@ namespace MSCO
|
|||||||
return attached;
|
return attached;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsAttached(SyncedBody b)
|
bool IsAttached(SyncedBody b)
|
||||||
{
|
{
|
||||||
if (b.IsVehicle || b.Rb == null) return false;
|
if (b.IsVehicle || b.Rb == null) return false;
|
||||||
// Unter einem anderen Rigidbody (z.B. am Auto eingehängt)
|
// Unter einem anderen Rigidbody (z.B. am Auto eingehängt)
|
||||||
for (Transform p = b.Rb.transform.parent; p != null; p = p.parent)
|
for (Transform p = b.Rb.transform.parent; p != null; p = p.parent)
|
||||||
if (p.GetComponent<Rigidbody>() != null) return true;
|
if (p.GetComponent<Rigidbody>() != 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<Joint>() == null) return false;
|
||||||
|
Transform playerRoot = Head != null ? Head.root : null;
|
||||||
foreach (Joint j in b.Rb.GetComponents<Joint>())
|
foreach (Joint j in b.Rb.GetComponents<Joint>())
|
||||||
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+15
-4
@@ -30,8 +30,13 @@ namespace MSCO
|
|||||||
public string Name, Text;
|
public string Name, Text;
|
||||||
public bool System;
|
public bool System;
|
||||||
public float Time;
|
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<ChatLine> visibleChat = new List<ChatLine>();
|
||||||
|
|
||||||
// Konsole
|
// Konsole
|
||||||
public bool ConsoleOpen { get; private set; }
|
public bool ConsoleOpen { get; private set; }
|
||||||
readonly List<string> consoleLines = new List<string>();
|
readonly List<string> consoleLines = new List<string>();
|
||||||
@@ -211,7 +216,8 @@ namespace MSCO
|
|||||||
int maxLines = ChatOpen ? 12 : 6;
|
int maxLines = ChatOpen ? 12 : 6;
|
||||||
|
|
||||||
// Sichtbare Zeilen: offen = die letzten, geschlossen = nur neue (blenden aus)
|
// Sichtbare Zeilen: offen = die letzten, geschlossen = nur neue (blenden aus)
|
||||||
var visible = new List<ChatLine>();
|
var visible = visibleChat;
|
||||||
|
visible.Clear();
|
||||||
for (int i = chat.Count - 1; i >= 0 && visible.Count < maxLines; i--)
|
for (int i = chat.Count - 1; i >= 0 && visible.Count < maxLines; i--)
|
||||||
if (ChatOpen || now - chat[i].Time < ChatFadeSeconds) visible.Insert(0, chat[i]);
|
if (ChatOpen || now - chat[i].Time < ChatFadeSeconds) visible.Insert(0, chat[i]);
|
||||||
|
|
||||||
@@ -233,9 +239,14 @@ namespace MSCO
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Vector2 size = chatName.CalcSize(new GUIContent(line.Name + ":"));
|
if (line.NameWidth < 0f)
|
||||||
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);
|
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;
|
y += lineHeight;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user