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:
+52
-11
@@ -21,7 +21,9 @@ namespace MSCO
|
||||
static readonly string[] Keywords =
|
||||
{
|
||||
"ignition", "starter", "engine", "light", "choke", "wiper", "hazard", "indicator", "turnsignal", "blinker",
|
||||
"horn", "heater", "fan", "radio", "key", "switch", "knob", "button"
|
||||
"horn", "heater", "fan", "radio", "key", "switch", "knob", "button",
|
||||
// Handbremse, Sonnenblenden, Sitzlehne, Gurt, CD-Spieler, Innenlicht, Tankdeckel
|
||||
"handbrake", "sunvisor", "seattop", "seatbelt", "cdplayer", "interiorlight", "opencap"
|
||||
};
|
||||
// Montage/Speichern/Schrauben - läuft über den Objekt- bzw. FSM-Sync, hier nicht anfassen
|
||||
static readonly string[] Excluded =
|
||||
@@ -51,6 +53,8 @@ namespace MSCO
|
||||
readonly Dictionary<int, Control> controls = new Dictionary<int, Control>();
|
||||
readonly HashSet<PlayMakerFSM> scanned = new HashSet<PlayMakerFSM>();
|
||||
readonly List<Control> outgoing = new List<Control>();
|
||||
// Zustände für Schalter, die wir noch nicht kennen (Teil noch nicht angebaut/aktiv, Server-Snapshot vor dem Suchlauf)
|
||||
readonly Dictionary<int, string> pending = new Dictionary<int, string>();
|
||||
float nextScan, nextCheck;
|
||||
|
||||
public int Count { get { return controls.Count; } }
|
||||
@@ -60,6 +64,7 @@ namespace MSCO
|
||||
{
|
||||
controls.Clear();
|
||||
scanned.Clear();
|
||||
pending.Clear();
|
||||
nextScan = -1f; // erster Suchlauf verteilt, siehe Update
|
||||
}
|
||||
|
||||
@@ -115,32 +120,68 @@ namespace MSCO
|
||||
int key = r.ReadInt32();
|
||||
string state = r.ReadString();
|
||||
Control c;
|
||||
if (!controls.TryGetValue(key, out c) || c.Fsm == null) { nextScan = 0f; continue; }
|
||||
if (!controls.TryGetValue(key, out c) || c.Fsm == null) { pending[key] = state; nextScan = 0f; continue; }
|
||||
if (objects.VehicleOwner(c.Root) == localId) continue; // ich fahre: meine Schalter gelten
|
||||
if (c.Fsm.ActiveStateName == state) { c.LastState = state; continue; }
|
||||
FsmState target = c.Fsm.Fsm.GetState(state);
|
||||
if (target == null) continue;
|
||||
c.LastState = state; // nicht als eigene Änderung zurückschicken
|
||||
FsmSync.SwitchStateSilently(c.Fsm, target);
|
||||
c.LastState = c.Fsm.ActiveStateName; // FSM kann sofort weiterschalten (z.B. "Start" -> "Running")
|
||||
SwitchTo(c, state);
|
||||
}
|
||||
}
|
||||
|
||||
void SwitchTo(Control c, string state)
|
||||
{
|
||||
if (c.Fsm.ActiveStateName == state) { c.LastState = state; return; }
|
||||
FsmState target = c.Fsm.Fsm.GetState(state);
|
||||
if (target == null) return;
|
||||
c.LastState = state; // nicht als eigene Änderung zurückschicken
|
||||
FsmSync.SwitchStateSilently(c.Fsm, target);
|
||||
c.LastState = c.Fsm.ActiveStateName; // FSM kann sofort weiterschalten (z.B. "Start" -> "Running")
|
||||
}
|
||||
|
||||
void Scan()
|
||||
{
|
||||
int before = controls.Count;
|
||||
foreach (PlayMakerFSM fsm in SceneCache.Fsms(20f))
|
||||
{
|
||||
if (fsm == null || !scanned.Add(fsm)) continue;
|
||||
if (fsm == null || scanned.Contains(fsm)) continue;
|
||||
string root = fsm.transform.root.name;
|
||||
if (!IsVehicle(root) || !Wanted(fsm.gameObject.name, fsm.FsmName)) continue;
|
||||
// Noch nicht am Fahrzeug (z.B. Radio liegt in CARPARTS): beim nächsten Suchlauf nochmal ansehen
|
||||
if (!IsVehicle(root)) continue;
|
||||
scanned.Add(fsm);
|
||||
if (!Wanted(fsm.gameObject.name, fsm.FsmName)) continue;
|
||||
int key = Hash(FsmSync.PathOf(fsm.transform) + "|" + fsm.FsmName);
|
||||
if (controls.ContainsKey(key)) continue;
|
||||
controls[key] = new Control { Key = key, Root = root, Fsm = fsm, LastState = fsm.ActiveStateName, WindowStart = Time.time };
|
||||
var control = new Control { Key = key, Root = root, Fsm = fsm, LastState = fsm.ActiveStateName, WindowStart = Time.time };
|
||||
controls[key] = control;
|
||||
string waiting;
|
||||
if (pending.TryGetValue(key, out waiting)) { pending.Remove(key); SwitchTo(control, waiting); }
|
||||
}
|
||||
if (controls.Count != before) MscoLog.Info("[MSCO] Vehicle controls (ignition, lights, engine ...): " + controls.Count + " synced");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// P2P-Host: alle Schalterzustände nochmal schicken (Licht an, Motor läuft ...) - für später Beigetretene und
|
||||
/// falls eine Nachricht verloren ging. Fahrzeuge, die ein anderer fährt, gibt dieser vor.
|
||||
/// </summary>
|
||||
public void ResendAll(ObjectSync objects, int localId, Action<MsgType, byte[]> send)
|
||||
{
|
||||
outgoing.Clear();
|
||||
foreach (Control c in controls.Values)
|
||||
{
|
||||
if (c.Fsm == null || c.Muted || string.IsNullOrEmpty(c.Fsm.ActiveStateName)) continue;
|
||||
int owner = objects.VehicleOwner(c.Root);
|
||||
if (owner != SyncedBody.NoOwner && owner != localId) continue;
|
||||
outgoing.Add(c);
|
||||
}
|
||||
for (int start = 0; start < outgoing.Count; start += MaxPerMessage)
|
||||
{
|
||||
int from = start, count = Math.Min(MaxPerMessage, outgoing.Count - start);
|
||||
send(MsgType.VehicleControls, NetSession.Build(w =>
|
||||
{
|
||||
w.Write(count);
|
||||
for (int i = from; i < from + count; i++) { w.Write(outgoing[i].Key); w.Write(outgoing[i].Fsm.ActiveStateName); }
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
static bool Wanted(string objectName, string fsmName)
|
||||
{
|
||||
string o = objectName.ToLower(), f = fsmName.ToLower();
|
||||
|
||||
Reference in New Issue
Block a user