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:
+99
-7
@@ -52,6 +52,7 @@ namespace MSCO
|
||||
readonly LobbyUI lobby = new LobbyUI();
|
||||
readonly ObjectSync objects = new ObjectSync();
|
||||
readonly VehicleFx vehicleFx = new VehicleFx();
|
||||
readonly WheelSpin wheelSpin = new WheelSpin();
|
||||
readonly WorldSync worldSync = new WorldSync();
|
||||
readonly DiscordPresence discord = new DiscordPresence();
|
||||
readonly MoneySync moneySync = new MoneySync();
|
||||
@@ -59,6 +60,9 @@ namespace MSCO
|
||||
readonly Passenger passenger = new Passenger();
|
||||
readonly SteamLobby steam = new SteamLobby();
|
||||
readonly VehicleStateSync vehicleState = new VehicleStateSync();
|
||||
readonly DamageSync damageSync = new DamageSync();
|
||||
readonly WorldVarSync worldVars = new WorldVarSync();
|
||||
readonly TrafficSync traffic = new TrafficSync();
|
||||
readonly Overlays overlays = new Overlays();
|
||||
bool isAdmin; // Server hat uns als Admin gemeldet
|
||||
readonly HashSet<string> bannedNames = new HashSet<string>(); // P2P-Host: für diese Sitzung gebannt
|
||||
@@ -96,6 +100,26 @@ namespace MSCO
|
||||
Application.runInBackground = true;
|
||||
playerName = PlayerPrefs.GetString(PrefName, System.Environment.UserName);
|
||||
objects.Send = SendGame;
|
||||
// Einkäufe / verbrauchte Items bei uns: allen melden
|
||||
objects.ItemAppeared = b =>
|
||||
{
|
||||
Vector3 pos = b.Rb.position;
|
||||
Quaternion rot = b.Rb.rotation;
|
||||
string name = b.Go.name;
|
||||
int id = b.Id;
|
||||
SendGame(MsgType.ItemAppeared, NetSession.Build(w =>
|
||||
{
|
||||
w.Write(id);
|
||||
w.Write(name);
|
||||
w.Write(pos.x); w.Write(pos.y); w.Write(pos.z);
|
||||
w.Write(rot.x); w.Write(rot.y); w.Write(rot.z); w.Write(rot.w);
|
||||
}));
|
||||
};
|
||||
objects.ItemDestroyed = b =>
|
||||
{
|
||||
int id = b.Id;
|
||||
SendGame(MsgType.ObjDestroy, NetSession.Build(w => w.Write(id)));
|
||||
};
|
||||
FsmSync.Init();
|
||||
SafetyPatches.Apply(); // verhindert den Absturz durch Kreis in der Objekt-Hierarchie
|
||||
discord.Start();
|
||||
@@ -182,6 +206,9 @@ namespace MSCO
|
||||
var lines = objects.DescribeVehicles();
|
||||
lines.Add("tracked doors/gates/hoods: " + doorSync.Count);
|
||||
lines.Add("synced vehicle values (fuel, oil, bolts, wear ...): " + vehicleState.Count);
|
||||
lines.Add("synced body meshes (crash damage): " + damageSync.Count);
|
||||
lines.Add("synced job/shop values: " + worldVars.Count);
|
||||
lines.Add("synced traffic cars: " + traffic.Count + (IsWorldAuthority ? " (simulated here)" : " (following)"));
|
||||
return lines;
|
||||
}
|
||||
|
||||
@@ -357,6 +384,7 @@ namespace MSCO
|
||||
Vector3 pos = head.position + forward * 1.2f;
|
||||
Quaternion rot = Quaternion.LookRotation(forward, Vector3.up);
|
||||
if (!ItemSpawner.Spawn(item, pos, rot)) { overlays.Log("No '" + item + "' in this game"); return; }
|
||||
objects.MarkNetworkCreated(ItemSpawner.LastSpawned); // wird per SpawnItem gemeldet, nicht als "gekauft"
|
||||
rescanSoon = true;
|
||||
SendGame(MsgType.SpawnItem, NetSession.Build(w =>
|
||||
{
|
||||
@@ -374,7 +402,22 @@ namespace MSCO
|
||||
var pos = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle());
|
||||
var rot = new Quaternion(r.ReadSingle(), r.ReadSingle(), r.ReadSingle(), r.ReadSingle());
|
||||
if (!ItemSpawner.IsKnown(item) || item == ItemSpawner.RatchetSet) return false; // nur bekannte Gegenstände
|
||||
return ItemSpawner.Spawn(item, pos, rot);
|
||||
bool ok = ItemSpawner.Spawn(item, pos, rot);
|
||||
if (ok && Instance != null) Instance.objects.MarkNetworkCreated(ItemSpawner.LastSpawned);
|
||||
return ok;
|
||||
}
|
||||
|
||||
/// <summary>Bei einem anderen Spieler ist ein Item aufgetaucht (Einkauf ...): hier auch erzeugen.</summary>
|
||||
bool ApplyAppeared(BinaryReader r)
|
||||
{
|
||||
int id = r.ReadInt32();
|
||||
string name = r.ReadString();
|
||||
var pos = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle());
|
||||
var rot = new Quaternion(r.ReadSingle(), r.ReadSingle(), r.ReadSingle(), r.ReadSingle());
|
||||
if (objects.HasNear(id, pos, 5f)) return false; // haben wir schon (z.B. war nur kurz ausgeblendet)
|
||||
if (!ItemSpawner.SpawnObjectNamed(name, pos, rot)) return false;
|
||||
objects.MarkNetworkCreated(ItemSpawner.LastSpawned);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>Admin: Bann aufheben (Server: SteamID oder name:..., P2P: Name).</summary>
|
||||
@@ -926,11 +969,11 @@ namespace MSCO
|
||||
foreach (PlayerInfo p in players.Values) DestroyAvatar(p);
|
||||
players.Clear();
|
||||
objects.Reset();
|
||||
vehicleFx.Reset();
|
||||
vehicleFx.Reset(); wheelSpin.Reset();
|
||||
worldSync.Reset();
|
||||
moneySync.Reset();
|
||||
doorSync.Reset();
|
||||
vehicleState.Reset();
|
||||
vehicleState.Reset(); damageSync.Reset(); worldVars.Reset(); traffic.Reset();
|
||||
isAdmin = false;
|
||||
if (overlays.AdminOpen || overlays.ChatOpen) overlays.CloseAll();
|
||||
FsmSync.Enabled = false;
|
||||
@@ -957,7 +1000,9 @@ namespace MSCO
|
||||
{
|
||||
return t == MsgType.Player || t == MsgType.ObjStates || t == MsgType.ObjOwn
|
||||
|| t == MsgType.ObjRelease || t == MsgType.FsmEvent || t == MsgType.VehicleFx || t == MsgType.WorldTime || t == MsgType.MoneyDelta || t == MsgType.DoorState
|
||||
|| t == MsgType.Chat || t == MsgType.VarSync || t == MsgType.SpawnItem;
|
||||
|| t == MsgType.Chat || t == MsgType.VarSync || t == MsgType.SpawnItem
|
||||
|| t == MsgType.ItemAppeared || t == MsgType.ObjDestroy || t == MsgType.VehicleDamage
|
||||
|| t == MsgType.TrafficStates || t == MsgType.WorldVars;
|
||||
}
|
||||
|
||||
void OnMessage(int peerId, Message m)
|
||||
@@ -1245,9 +1290,24 @@ namespace MSCO
|
||||
case MsgType.VarSync:
|
||||
vehicleState.Handle(from, r, objects, localId);
|
||||
break;
|
||||
case MsgType.VehicleDamage:
|
||||
damageSync.Handle(r);
|
||||
break;
|
||||
case MsgType.WorldVars:
|
||||
worldVars.Handle(r);
|
||||
break;
|
||||
case MsgType.TrafficStates:
|
||||
traffic.Handle(r, IsWorldAuthority);
|
||||
break;
|
||||
case MsgType.SpawnItem:
|
||||
if (ApplySpawn(r)) rescanSoon = true; // neues Item gleich in den Objekt-Sync aufnehmen
|
||||
break;
|
||||
case MsgType.ItemAppeared:
|
||||
if (ApplyAppeared(r)) rescanSoon = true;
|
||||
break;
|
||||
case MsgType.ObjDestroy:
|
||||
objects.DestroyRemote(r.ReadInt32());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1356,8 +1416,8 @@ namespace MSCO
|
||||
passenger.Reset();
|
||||
localPlayer = null;
|
||||
objects.OnGameLoaded();
|
||||
vehicleState.Reset();
|
||||
vehicleFx.Reset();
|
||||
vehicleState.Reset(); damageSync.Reset(); worldVars.Reset(); traffic.Reset();
|
||||
vehicleFx.Reset(); wheelSpin.Reset();
|
||||
worldSync.Reset();
|
||||
moneySync.Reset();
|
||||
doorSync.Reset();
|
||||
@@ -1377,7 +1437,7 @@ namespace MSCO
|
||||
passenger.Reset();
|
||||
localPlayer = null;
|
||||
objects.Reset();
|
||||
vehicleFx.Reset();
|
||||
vehicleFx.Reset(); wheelSpin.Reset();
|
||||
worldSync.Reset();
|
||||
moneySync.Reset();
|
||||
doorSync.Reset();
|
||||
@@ -1477,6 +1537,15 @@ namespace MSCO
|
||||
// Gesamtzustand der Fahrzeuge (Tank, Öl, Verschleiß ...)
|
||||
try { if (objects.ScanComplete) vehicleState.Update(objects, localId, SendGame); }
|
||||
catch (System.Exception e) { ReportError("vehicle state sync", e); }
|
||||
// Unfallschäden (verbeulte Karosserie)
|
||||
try { if (objects.ScanComplete) damageSync.Update(objects, localId, SendGame); }
|
||||
catch (System.Exception e) { ReportError("crash damage sync", e); }
|
||||
// Jobs, Aufträge, Laden
|
||||
try { if (objects.ScanComplete) worldVars.Update(SendGame); }
|
||||
catch (System.Exception e) { ReportError("jobs/shop sync", e); }
|
||||
// Verkehr: die Welt-Autorität simuliert, alle anderen fahren nach
|
||||
try { if (objects.ScanComplete) traffic.Update(IsWorldAuthority, Time.deltaTime, SendGame); }
|
||||
catch (System.Exception e) { ReportError("traffic sync", e); }
|
||||
}
|
||||
|
||||
foreach (PlayerInfo p in players.Values)
|
||||
@@ -1523,6 +1592,8 @@ namespace MSCO
|
||||
if (!IsPeerReady || !MenuHelper.InGame) return;
|
||||
try { objects.FixedUpdate(); }
|
||||
catch (System.Exception e) { ReportError("object movement", e); }
|
||||
try { traffic.FixedUpdate(); }
|
||||
catch (System.Exception e) { ReportError("traffic movement", e); }
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
@@ -1531,6 +1602,8 @@ namespace MSCO
|
||||
// Nach den Spiel-FSMs, damit Lichter/Motorgeräusch der Fahrzeuge anderer gewinnen
|
||||
try { if (IsPeerReady && MenuHelper.InGame) vehicleFx.Apply(objects); }
|
||||
catch (System.Exception e) { ReportError("vehicle lights/sound", e); }
|
||||
try { if (IsPeerReady && MenuHelper.InGame) wheelSpin.Apply(objects, Time.deltaTime); }
|
||||
catch (System.Exception e) { ReportError("wheels", e); }
|
||||
// Beifahrer nach der Fahrzeugbewegung auf den Sitz setzen
|
||||
try { if (localPlayer != null && MenuHelper.InGame) passenger.LateUpdate(localPlayer, playerCamera, objects); }
|
||||
catch (System.Exception e) { ReportError("passenger", e); }
|
||||
@@ -1620,9 +1693,28 @@ namespace MSCO
|
||||
}
|
||||
}
|
||||
|
||||
// Seit dem letzten Spielstand gekaufte bzw. verbrauchte Items
|
||||
var destroyedIds = new List<int>();
|
||||
if (r.BaseStream.Length - r.BaseStream.Position >= 4)
|
||||
{
|
||||
int appeared = r.ReadInt32();
|
||||
for (int i = 0; i < appeared; i++)
|
||||
{
|
||||
byte[] payload = r.ReadBytes(r.ReadInt32());
|
||||
try { ApplyAppeared(new BinaryReader(new MemoryStream(payload))); }
|
||||
catch (System.Exception e) { MscoLog.Warning("Could not restore a bought item: " + e.Message); }
|
||||
}
|
||||
}
|
||||
if (r.BaseStream.Length - r.BaseStream.Position >= 4)
|
||||
{
|
||||
int destroyed = r.ReadInt32();
|
||||
for (int i = 0; i < destroyed; i++) destroyedIds.Add(r.ReadInt32());
|
||||
}
|
||||
|
||||
// Abgebaute Teile und gespawnte Items sind jetzt eigene Objekte: erfassen, dann alle Positionen setzen
|
||||
yield return null;
|
||||
objects.ScanNow();
|
||||
foreach (int id in destroyedIds) objects.DestroyRemote(id);
|
||||
int applied = 0;
|
||||
foreach (KeyValuePair<int, Pose> p in poses)
|
||||
if (objects.ApplySnapshotPose(p.Key, p.Value.Position, p.Value.Rotation)) applied++;
|
||||
|
||||
Reference in New Issue
Block a user