Satsuma: sync part state from CARPARTS/Database, paint, late-installed parts, more controls

- VehicleStateSync also tracks the CARPARTS and Database roots (wear, damaged
  parts, tire wear, oilpan oil, battery charge, carb/ignition settings,
  suspension, odometer); the Satsuma's driver is authoritative for them
- Paint colors (FsmColor) as four float channels (compatible with old servers)
  and applied to the part's material
- FSMs are re-examined when a part is installed/removed (path changes);
  before, anything not on the car at the first scan was never synced
- ControlSync: handbrake, sun visors, seat recline, seat belt, CD player,
  interior light; pending states for controls not found yet
- Late joiners: job/shop values and switch states from the server snapshot;
  P2P host resends all switch states every 15 s

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-02 14:10:42 +02:00
co-authored by Claude Opus 5.5
parent 0b2834282d
commit 3b83644ce9
6 changed files with 221 additions and 34 deletions
+22 -3
View File
@@ -41,6 +41,8 @@ namespace MSCO
readonly Dictionary<int, Var> vars = new Dictionary<int, Var>();
readonly HashSet<PlayMakerFSM> scanned = new HashSet<PlayMakerFSM>();
readonly List<Var> outgoing = new List<Var>();
// Werte für noch nicht gefundene FSMs (Server-Snapshot vor dem ersten Suchlauf): [typ, wert]
readonly Dictionary<int, KeyValuePair<byte, int>> pending = new Dictionary<int, KeyValuePair<byte, int>>();
float nextScan, nextCheck;
public int Count { get { return vars.Count; } }
@@ -49,6 +51,7 @@ namespace MSCO
{
vars.Clear();
scanned.Clear();
pending.Clear();
nextScan = -1f; // erster Suchlauf verteilt, siehe Update
}
@@ -102,9 +105,13 @@ namespace MSCO
int iv = 0; bool bv = false;
if (type == 2) iv = r.ReadInt32(); else if (type == 3) bv = r.ReadBoolean(); else return;
Var v;
if (!vars.TryGetValue(key, out v) || v.Type != type) continue;
if (type == 2) ((FsmInt)v.Variable).Value = iv; else ((FsmBool)v.Variable).Value = bv;
Remember(v); // nicht zurückschicken
if (!vars.TryGetValue(key, out v))
{
if (pending.Count < 20000) pending[key] = new KeyValuePair<byte, int>(type, type == 2 ? iv : (bv ? 1 : 0));
continue;
}
if (v.Type != type) continue;
Set(v, type == 2 ? iv : (bv ? 1 : 0));
}
}
@@ -131,6 +138,18 @@ namespace MSCO
var v = new Var { Key = key, Variable = variable, Type = type };
Remember(v);
vars[key] = v;
KeyValuePair<byte, int> waiting;
if (pending.TryGetValue(key, out waiting))
{
pending.Remove(key);
if (waiting.Key == type) Set(v, waiting.Value);
}
}
static void Set(Var v, int value)
{
if (v.Type == 2) ((FsmInt)v.Variable).Value = value; else ((FsmBool)v.Variable).Value = value != 0;
Remember(v); // nicht zurückschicken
}
static bool Changed(Var v)