Join: replay part actions first, then rescan and place objects (detached parts no longer stuck in the car); rescan right after remote disassembly; lift out bodies that keep getting flung
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+30
-3
@@ -41,6 +41,7 @@ namespace MSCO
|
||||
bool dedicated; // verbunden mit einem dedizierten Server
|
||||
bool connectingToServer; // Verbindungsaufbau zu einem dedizierten Server läuft
|
||||
bool readySent; // Server: Weltzustand schon angefordert
|
||||
bool rescanSoon; // nach einer Abbau-Aktion neue lose Teile sofort erfassen
|
||||
byte[] pendingSnapshot; // Server: Weltzustand, wartet auf Objekt-Suchlauf
|
||||
const int SnapshotEventsPerFrame = 20;
|
||||
readonly ServerBrowser browser = new ServerBrowser();
|
||||
@@ -1041,8 +1042,14 @@ namespace MSCO
|
||||
objects.Handle(from, type, r);
|
||||
break;
|
||||
case MsgType.FsmEvent:
|
||||
FsmSync.Apply(FsmEventMsg.Deserialize(r));
|
||||
{
|
||||
FsmEventMsg msg = FsmEventMsg.Deserialize(r);
|
||||
FsmSync.Apply(msg);
|
||||
// Ein Teil wurde abgebaut: gleich als loses Objekt erfassen, damit es der Hand des Mitspielers
|
||||
// folgt, statt Sekunden lang im Auto zu stecken (die Physik würde es samt Auto wegschleudern)
|
||||
if (msg.EventName == "DISASSEMBLE" || msg.EventName == "REMOVE" || msg.EventName == "UNINSTALL") rescanSoon = true;
|
||||
break;
|
||||
}
|
||||
case MsgType.WorldTime:
|
||||
worldSync.Apply(r);
|
||||
break;
|
||||
@@ -1218,6 +1225,11 @@ namespace MSCO
|
||||
}
|
||||
|
||||
if (teleportToHost) TryTeleportToHost();
|
||||
if (rescanSoon && objects.ScanComplete)
|
||||
{
|
||||
rescanSoon = false;
|
||||
objects.ScanNow();
|
||||
}
|
||||
|
||||
// Dedizierter Server: nach dem ersten Objekt-Suchlauf den Weltzustand anfordern und anwenden
|
||||
if (dedicated && handshakeDone && !readySent && objects.ScanComplete)
|
||||
@@ -1365,14 +1377,16 @@ namespace MSCO
|
||||
if (localPlayer != null) localPlayer.position = spawn + Vector3.up * 0.2f;
|
||||
}
|
||||
|
||||
// Positionen erst merken: sie werden NACH den Montage-Aktionen gesetzt. Sonst steckt ein Teil, das eine
|
||||
// nachgespielte Aktion vom Auto löst, noch im Auto - die Physik schleudert es dann samt Auto weg.
|
||||
int objectCount = r.ReadInt32();
|
||||
int applied = 0;
|
||||
var poses = new List<KeyValuePair<int, Pose>>(objectCount);
|
||||
for (int i = 0; i < objectCount; i++)
|
||||
{
|
||||
int id = r.ReadInt32();
|
||||
var pos = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle());
|
||||
var rot = new Quaternion(r.ReadSingle(), r.ReadSingle(), r.ReadSingle(), r.ReadSingle());
|
||||
if (objects.ApplySnapshotPose(id, pos, rot)) applied++;
|
||||
poses.Add(new KeyValuePair<int, Pose>(id, new Pose { Position = pos, Rotation = rot }));
|
||||
}
|
||||
|
||||
int eventCount = r.ReadInt32();
|
||||
@@ -1383,6 +1397,13 @@ namespace MSCO
|
||||
if ((i + 1) % SnapshotEventsPerFrame == 0) yield return null; // nicht alles in einem Frame
|
||||
}
|
||||
|
||||
// Abgebaute Teile sind jetzt eigene Objekte: erfassen, dann alle Positionen setzen
|
||||
yield return null;
|
||||
objects.ScanNow();
|
||||
int applied = 0;
|
||||
foreach (KeyValuePair<int, Pose> p in poses)
|
||||
if (objects.ApplySnapshotPose(p.Key, p.Value.Position, p.Value.Rotation)) applied++;
|
||||
|
||||
// Geld: Summe aller Änderungen seit dem Spielstand des Servers
|
||||
if (r.BaseStream.Length - r.BaseStream.Position >= 4) moneySync.Apply(r.ReadSingle());
|
||||
|
||||
@@ -1400,6 +1421,12 @@ namespace MSCO
|
||||
SetStatus("Connected");
|
||||
}
|
||||
|
||||
struct Pose
|
||||
{
|
||||
public Vector3 Position;
|
||||
public Quaternion Rotation;
|
||||
}
|
||||
|
||||
/// <summary>Sobald die erste Position des Hosts da ist: seitlich neben ihn stellen.</summary>
|
||||
void TryTeleportToHost()
|
||||
{
|
||||
|
||||
+28
-4
@@ -31,6 +31,9 @@ namespace MSCO
|
||||
// wird dann NICHT als loses Objekt synchronisiert - sonst reißt das Gelenk und das Teil fliegt weg
|
||||
public bool Attached;
|
||||
public float NextAttachCheck;
|
||||
// Wie oft kurz hintereinander weggeschleudert (steckt es in etwas fest?)
|
||||
public int RunawayCount;
|
||||
public float RunawayWindowStart;
|
||||
|
||||
public Vector3 TargetPos;
|
||||
public Quaternion TargetRot;
|
||||
@@ -528,13 +531,27 @@ namespace MSCO
|
||||
if (rb.isKinematic || rb.velocity.sqrMagnitude < RunawaySpeed * RunawaySpeed) return;
|
||||
rb.velocity = Vector3.zero;
|
||||
rb.angularVelocity = Vector3.zero;
|
||||
if (IsLocal(b) && b.LastSentTime > 0f && IsValidPose(b.LastSentPos, b.LastSentRot))
|
||||
|
||||
// Mehrmals kurz hintereinander: das Objekt steckt in etwas fest (z.B. abgebautes Teil im Auto).
|
||||
// Dann nicht wieder an dieselbe Stelle setzen, sondern nach oben heraus heben.
|
||||
if (Time.time - b.RunawayWindowStart > 5f) { b.RunawayWindowStart = Time.time; b.RunawayCount = 0; }
|
||||
b.RunawayCount++;
|
||||
bool stuck = b.RunawayCount >= 3;
|
||||
if (stuck)
|
||||
{
|
||||
rb.transform.position = AboveGround(b.LastSentPos, rb.transform);
|
||||
Bounds bounds = new Bounds(rb.worldCenterOfMass, Vector3.zero);
|
||||
foreach (Collider c in rb.GetComponentsInChildren<Collider>()) bounds.Encapsulate(c.bounds);
|
||||
rb.transform.position += Vector3.up * (bounds.size.y + 1.5f);
|
||||
b.RunawayCount = 0;
|
||||
}
|
||||
else if (IsLocal(b) && b.LastSentTime > 0f && IsValidPose(b.LastSentPos, b.LastSentRot))
|
||||
{
|
||||
rb.transform.position = b.LastSentPos;
|
||||
rb.transform.rotation = b.LastSentRot;
|
||||
}
|
||||
else rb.transform.position = AboveGround(rb.position, rb.transform);
|
||||
ModConsole.Warning("[MSCO] Stopped " + b.RootName + " - it was flung away by the physics");
|
||||
b.NoMotionClaimUntil = Time.time + HandoverCooldown;
|
||||
if (b.RunawayCount <= 1 || stuck)
|
||||
ModConsole.Warning("[MSCO] Stopped " + b.RootName + " - it was flung away by the physics" + (stuck ? " (stuck, lifted out)" : ""));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -745,6 +762,13 @@ namespace MSCO
|
||||
|
||||
// ---------------------------------------------------------------- Registrierung
|
||||
|
||||
/// <summary>Sofort nach neuen Objekten suchen (z.B. nach dem Nachspielen von Montage-Aktionen).</summary>
|
||||
public void ScanNow()
|
||||
{
|
||||
Scan();
|
||||
nextScan = Time.time + ScanInterval;
|
||||
}
|
||||
|
||||
/// <summary>Neue Rigidbodies suchen (gekaufte Items, abmontierte Teile ...).</summary>
|
||||
void Scan()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user