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 dedicated; // verbunden mit einem dedizierten Server
|
||||||
bool connectingToServer; // Verbindungsaufbau zu einem dedizierten Server läuft
|
bool connectingToServer; // Verbindungsaufbau zu einem dedizierten Server läuft
|
||||||
bool readySent; // Server: Weltzustand schon angefordert
|
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
|
byte[] pendingSnapshot; // Server: Weltzustand, wartet auf Objekt-Suchlauf
|
||||||
const int SnapshotEventsPerFrame = 20;
|
const int SnapshotEventsPerFrame = 20;
|
||||||
readonly ServerBrowser browser = new ServerBrowser();
|
readonly ServerBrowser browser = new ServerBrowser();
|
||||||
@@ -1041,8 +1042,14 @@ namespace MSCO
|
|||||||
objects.Handle(from, type, r);
|
objects.Handle(from, type, r);
|
||||||
break;
|
break;
|
||||||
case MsgType.FsmEvent:
|
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;
|
break;
|
||||||
|
}
|
||||||
case MsgType.WorldTime:
|
case MsgType.WorldTime:
|
||||||
worldSync.Apply(r);
|
worldSync.Apply(r);
|
||||||
break;
|
break;
|
||||||
@@ -1218,6 +1225,11 @@ namespace MSCO
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (teleportToHost) TryTeleportToHost();
|
if (teleportToHost) TryTeleportToHost();
|
||||||
|
if (rescanSoon && objects.ScanComplete)
|
||||||
|
{
|
||||||
|
rescanSoon = false;
|
||||||
|
objects.ScanNow();
|
||||||
|
}
|
||||||
|
|
||||||
// Dedizierter Server: nach dem ersten Objekt-Suchlauf den Weltzustand anfordern und anwenden
|
// Dedizierter Server: nach dem ersten Objekt-Suchlauf den Weltzustand anfordern und anwenden
|
||||||
if (dedicated && handshakeDone && !readySent && objects.ScanComplete)
|
if (dedicated && handshakeDone && !readySent && objects.ScanComplete)
|
||||||
@@ -1365,14 +1377,16 @@ namespace MSCO
|
|||||||
if (localPlayer != null) localPlayer.position = spawn + Vector3.up * 0.2f;
|
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 objectCount = r.ReadInt32();
|
||||||
int applied = 0;
|
var poses = new List<KeyValuePair<int, Pose>>(objectCount);
|
||||||
for (int i = 0; i < objectCount; i++)
|
for (int i = 0; i < objectCount; i++)
|
||||||
{
|
{
|
||||||
int id = r.ReadInt32();
|
int id = r.ReadInt32();
|
||||||
var pos = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle());
|
var pos = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle());
|
||||||
var rot = new Quaternion(r.ReadSingle(), 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();
|
int eventCount = r.ReadInt32();
|
||||||
@@ -1383,6 +1397,13 @@ namespace MSCO
|
|||||||
if ((i + 1) % SnapshotEventsPerFrame == 0) yield return null; // nicht alles in einem Frame
|
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
|
// Geld: Summe aller Änderungen seit dem Spielstand des Servers
|
||||||
if (r.BaseStream.Length - r.BaseStream.Position >= 4) moneySync.Apply(r.ReadSingle());
|
if (r.BaseStream.Length - r.BaseStream.Position >= 4) moneySync.Apply(r.ReadSingle());
|
||||||
|
|
||||||
@@ -1400,6 +1421,12 @@ namespace MSCO
|
|||||||
SetStatus("Connected");
|
SetStatus("Connected");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Pose
|
||||||
|
{
|
||||||
|
public Vector3 Position;
|
||||||
|
public Quaternion Rotation;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Sobald die erste Position des Hosts da ist: seitlich neben ihn stellen.</summary>
|
/// <summary>Sobald die erste Position des Hosts da ist: seitlich neben ihn stellen.</summary>
|
||||||
void TryTeleportToHost()
|
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
|
// wird dann NICHT als loses Objekt synchronisiert - sonst reißt das Gelenk und das Teil fliegt weg
|
||||||
public bool Attached;
|
public bool Attached;
|
||||||
public float NextAttachCheck;
|
public float NextAttachCheck;
|
||||||
|
// Wie oft kurz hintereinander weggeschleudert (steckt es in etwas fest?)
|
||||||
|
public int RunawayCount;
|
||||||
|
public float RunawayWindowStart;
|
||||||
|
|
||||||
public Vector3 TargetPos;
|
public Vector3 TargetPos;
|
||||||
public Quaternion TargetRot;
|
public Quaternion TargetRot;
|
||||||
@@ -528,13 +531,27 @@ namespace MSCO
|
|||||||
if (rb.isKinematic || rb.velocity.sqrMagnitude < RunawaySpeed * RunawaySpeed) return;
|
if (rb.isKinematic || rb.velocity.sqrMagnitude < RunawaySpeed * RunawaySpeed) return;
|
||||||
rb.velocity = Vector3.zero;
|
rb.velocity = Vector3.zero;
|
||||||
rb.angularVelocity = 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;
|
rb.transform.rotation = b.LastSentRot;
|
||||||
}
|
}
|
||||||
else rb.transform.position = AboveGround(rb.position, rb.transform);
|
b.NoMotionClaimUntil = Time.time + HandoverCooldown;
|
||||||
ModConsole.Warning("[MSCO] Stopped " + b.RootName + " - it was flung away by the physics");
|
if (b.RunawayCount <= 1 || stuck)
|
||||||
|
ModConsole.Warning("[MSCO] Stopped " + b.RootName + " - it was flung away by the physics" + (stuck ? " (stuck, lifted out)" : ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -745,6 +762,13 @@ namespace MSCO
|
|||||||
|
|
||||||
// ---------------------------------------------------------------- Registrierung
|
// ---------------------------------------------------------------- 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>
|
/// <summary>Neue Rigidbodies suchen (gekaufte Items, abmontierte Teile ...).</summary>
|
||||||
void Scan()
|
void Scan()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user