diff --git a/README.md b/README.md index f063f1d..ea7a40d 100644 --- a/README.md +++ b/README.md @@ -133,7 +133,7 @@ Fehlende Einstellungen ergänzt der Server beim Start automatisch. Umgebungsvari | `stop` | speichern und beenden | Im Spiel öffnen Admins mit `/admin` (Chat, Taste T) oder `admin` (F8-Konsole) das Admin-Menü: Kick/Ban, -GOTO/BRING (zu einem Spieler / Spieler zu sich teleportieren) und Cheats (Geld, Bedürfnisse auffüllen). +GOTO/BRING (zu einem Spieler / Spieler zu sich teleportieren) und Cheats (Geld, Bedürfnisse auffüllen, Satsuma zu sich holen). Cheats werden allen im Chat angezeigt, Teleports stehen im Server-Log. Der Chat landet auch im Server-Log. diff --git a/WorldState.cs b/WorldState.cs index e278418..c281827 100644 --- a/WorldState.cs +++ b/WorldState.cs @@ -79,14 +79,32 @@ public sealed class WorldState void ReadPose(BinaryReader r) { int id = r.ReadInt32(); + var p = new float[3]; + var q = new float[4]; + for (int k = 0; k < 3; k++) p[k] = r.ReadSingle(); + for (int k = 0; k < 4; k++) q[k] = r.ReadSingle(); + r.ReadSingle(); r.ReadSingle(); r.ReadSingle(); // Geschwindigkeit wird nicht gespeichert + + // Unsinnige Werte (Fehler, manipulierter Client) nicht speichern - sonst landet z.B. das Auto + // beim nächsten Beitreten im Boden oder außerhalb der Karte + if (!IsValidPose(p, q)) return; if (!Objects.TryGetValue(id, out var pose)) { - pose = new ObjectPose(); // bei voller Liste nur mitlesen, nicht speichern - if (Objects.Count < MaxObjects) Objects[id] = pose; + if (Objects.Count >= MaxObjects) return; + Objects[id] = pose = new ObjectPose(); } - for (int k = 0; k < 3; k++) pose.P[k] = r.ReadSingle(); - for (int k = 0; k < 4; k++) pose.R[k] = r.ReadSingle(); - r.ReadSingle(); r.ReadSingle(); r.ReadSingle(); // Geschwindigkeit wird nicht gespeichert + pose.P = p; + pose.R = q; + } + + /// Position innerhalb der Karte, Drehung ein gültiges Quaternion. + public static bool IsValidPose(float[] p, float[] q) + { + foreach (float f in p) if (!float.IsFinite(f)) return false; + foreach (float f in q) if (!float.IsFinite(f)) return false; + if (Math.Abs(p[0]) > 6000 || Math.Abs(p[2]) > 6000 || p[1] < -200 || p[1] > 3000) return false; + float len = MathF.Sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]); + return len > 0.9f && len < 1.1f; } public void ApplyMoney(byte[] payload)