2.8: sync bought/consumed items, wheel spin, crash damage, jobs/shop, traffic

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-27 14:58:38 +02:00
co-authored by Claude Opus 5.5
parent 96e8790f0b
commit 2eb15f2166
12 changed files with 799 additions and 17 deletions
+50 -1
View File
@@ -16,6 +16,8 @@ namespace MSCO
public int Id;
public string Path;
public Rigidbody Rb;
public GameObject Go; // zum Unterscheiden: nur Rigidbody weg (angebaut) oder ganzes Objekt weg (verbraucht)
public Vector3 LastPos;
public bool IsVehicle;
public string RootName;
@@ -89,6 +91,32 @@ namespace MSCO
public int LocalId;
/// <summary>Senden an alle anderen Spieler (setzt der MultiplayerManager).</summary>
public Action<MsgType, byte[]> Send;
/// <summary>Neues Item bei uns aufgetaucht (Einkauf ...) bzw. bei uns verbraucht - der Manager meldet es allen.</summary>
public Action<SyncedBody> ItemAppeared, ItemDestroyed;
// Übers Netz erzeugte Items (nicht nochmal als "neu" melden)
readonly HashSet<GameObject> networkCreated = new HashSet<GameObject>();
Vector3 lastPlayerPos;
const float LocalEventRange = 8f; // Aufgetaucht/verbraucht in dieser Nähe = wir haben es ausgelöst
public void MarkNetworkCreated(GameObject go) { if (go != null) networkCreated.Add(go); }
/// <summary>Gibt es dieses Objekt bei uns schon an dieser Stelle? (dann nicht nochmal erzeugen)</summary>
public bool HasNear(int id, Vector3 pos, float range)
{
SyncedBody b;
return byId.TryGetValue(id, out b) && b.Rb != null && (b.Rb.position - pos).sqrMagnitude < range * range;
}
/// <summary>Ein anderer Spieler hat dieses Item verbraucht: bei uns auch entfernen.</summary>
public bool DestroyRemote(int id)
{
SyncedBody b;
if (!byId.TryGetValue(id, out b)) return false;
if (b.Go != null) UnityEngine.Object.Destroy(b.Go);
Unregister(b);
return true;
}
readonly Dictionary<int, SyncedBody> byId = new Dictionary<int, SyncedBody>();
readonly Dictionary<Rigidbody, SyncedBody> byRb = new Dictionary<Rigidbody, SyncedBody>();
@@ -207,6 +235,7 @@ namespace MSCO
byId.Clear();
byRb.Clear();
rejected.Clear();
networkCreated.Clear();
drivenName = null;
drivenCache = null;
ScanComplete = false;
@@ -252,6 +281,7 @@ namespace MSCO
public void Update(Transform player, float dt)
{
if (player != null) lastPlayerPos = player.position;
if (Time.time >= nextScan)
{
nextScan = Time.time + ScanInterval;
@@ -268,7 +298,17 @@ namespace MSCO
removeList.Clear();
foreach (SyncedBody b in byId.Values)
{
if (b.Rb == null) { removeList.Add(b); continue; } // z.B. Teil wurde montiert
if (b.Rb == null)
{
// Ganzes Objekt weg (gegessen, getrunken, verbraucht) - nicht nur der Rigidbody (Teil angebaut).
// Nur melden, wenn es bei uns passiert ist: wir besaßen es oder standen daneben.
if (b.Go == null && !b.IsVehicle && ItemDestroyed != null
&& (IsLocal(b) || (b.LastPos - lastPlayerPos).sqrMagnitude < LocalEventRange * LocalEventRange))
ItemDestroyed(b);
removeList.Add(b);
continue;
}
b.LastPos = b.Rb.position;
if (!b.Rb.gameObject.activeInHierarchy) continue;
if (UpdateAttached(b)) continue; // angebaut: bewegt sich mit dem Auto
@@ -847,12 +887,21 @@ namespace MSCO
Id = id,
Path = path,
Rb = c.Key,
Go = c.Key.gameObject,
LastPos = c.Key.position,
IsVehicle = c.Value,
RootName = c.Key.transform.root.name
};
byId[id] = b;
byRb[c.Key] = b;
added++;
// Neues Item nach dem ersten Suchlauf, bei uns in der Nähe und nicht übers Netz entstanden:
// wahrscheinlich gekauft / ausgepackt / geliefert - den anderen melden
bool isItem = !b.IsVehicle && b.Go.name.EndsWith("(itemx)");
if (ScanComplete && isItem && ItemAppeared != null && !networkCreated.Contains(b.Go)
&& (b.LastPos - lastPlayerPos).sqrMagnitude < LocalEventRange * LocalEventRange)
ItemAppeared(b);
}
if (added > 0) MscoLog.Info("[MSCO] Syncing " + byId.Count + " objects (+" + added + ")");
}