MSCO 2.10.3: bolt stages and part tightness synced, snap to pivot, admin tighten/loosen
- Every bolt (Screw FSM, stage 0-8) and every part's tightness (BoltCheck/Use "Tightness", counted by the tool) is synced as state - before only the bolt turned on other clients, the part stayed loose or tight there - Tightening a part (tool, admin, other player) snaps it exactly onto its pivot (installed parts sit at local 0), except screw-in parts and hinged doors/hoods - Admin VEHICLE tab: TIGHTEN/LOOSEN per part, TIGHTEN ALL/LOOSEN ALL, bolted/loose state - fsmdump "pivots": installed part offsets Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,18 @@
|
||||
# Changelog
|
||||
|
||||
## 2.10.3
|
||||
|
||||
**Schrauben synchron**
|
||||
- Jede Schraube wird jetzt als Stufe (0–8) übertragen und die Festigkeit jedes Teils dazu: vorher drehte sich beim
|
||||
Mitspieler nur die Schraube, sein Teil blieb „lose“ bzw. „fest“ (die Festigkeit zählt im Spiel das Werkzeug hoch) –
|
||||
Teile ließen sich dann nicht abbauen oder fielen ab
|
||||
- Wird ein Teil festgezogen (Werkzeug, Admin oder vom Mitspieler), springt es exakt auf seinen Halter – verrutschte
|
||||
Teile sitzen wieder richtig (nicht bei eingedrehten Teilen wie Zündkerzen/Ölfilter und nicht bei Türen/Hauben)
|
||||
|
||||
**Admin-Menü, Reiter VEHICLE**
|
||||
- Je Teil **TIGHTEN** / **LOOSEN** (alle Schrauben ganz fest bzw. ganz lose, wie mit dem Werkzeug) und oben
|
||||
**TIGHTEN ALL** / **LOOSEN ALL**; Anzeige „bolted“/„loose“; das Fenster ist auf diesem Reiter breiter
|
||||
|
||||
## 2.10.2
|
||||
|
||||
- **Beifahrer**: automatisch festgehalten wird man nur noch, wenn das Fahrzeug fährt (egal wer fährt) – am stehenden
|
||||
|
||||
+21
@@ -17,6 +17,7 @@ namespace MSCO
|
||||
public static string Write(string filter)
|
||||
{
|
||||
string[] filters = (filter ?? "").ToLowerInvariant().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (filter != null && filter.Trim().ToLowerInvariant() == "pivots") return WritePivots();
|
||||
if (filters.Length == 0) return "fsmdump <text>[,text2] - e.g. fsmdump garage";
|
||||
var sb = new StringBuilder();
|
||||
int count = 0;
|
||||
@@ -51,6 +52,26 @@ namespace MSCO
|
||||
return count + " FSM(s) written to " + file;
|
||||
}
|
||||
|
||||
/// <summary>Eingebaute Teile: Lage relativ zu ihrem Halter (pivot_...) - ist sie immer 0?</summary>
|
||||
static string WritePivots()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
int count = 0;
|
||||
foreach (Transform t in Resources.FindObjectsOfTypeAll<Transform>())
|
||||
{
|
||||
if (t == null || t.gameObject.hideFlags != HideFlags.None || !t.name.StartsWith("pivot_")) continue;
|
||||
foreach (Transform child in t)
|
||||
{
|
||||
count++;
|
||||
sb.Append(FsmSync.PathOf(child)).Append(" | pos ").Append(child.localPosition.ToString("F4"))
|
||||
.Append(" rot ").Append(child.localEulerAngles.ToString("F1")).Append(" active ").Append(child.gameObject.activeInHierarchy).AppendLine();
|
||||
}
|
||||
}
|
||||
string file = Path.Combine(Bootstrap.Folder ?? ".", "fsmdump.txt");
|
||||
File.WriteAllText(file, sb.ToString());
|
||||
return count + " installed part(s) written to " + file;
|
||||
}
|
||||
|
||||
static void Dump(StringBuilder sb, PlayMakerFSM fsm, string path)
|
||||
{
|
||||
sb.Append("==== ").Append(path).Append(" | ").Append(fsm.FsmName).Append(" | active ").Append(fsm.gameObject.activeInHierarchy)
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace MSCO
|
||||
/// Version der Mod. Kleine Updates: nur die dritte Stelle erhöhen (2.9.1, 2.9.2 ...) - sie bleiben mit
|
||||
/// Servern und Mitspielern derselben ersten zwei Stellen kompatibel.
|
||||
/// </summary>
|
||||
public const string ModVersion = "2.10.2";
|
||||
public const string ModVersion = "2.10.3";
|
||||
/// <summary>
|
||||
/// Netzwerk-Version (die ersten beiden Stellen). Nur erhöhen, wenn sich das Protokoll inkompatibel ändert - dann
|
||||
/// auch GameServer.ModVersion im Server.
|
||||
|
||||
+34
-3
@@ -270,7 +270,7 @@ namespace MSCO
|
||||
|
||||
void DrawAdmin(MultiplayerManager mp)
|
||||
{
|
||||
float width = Mathf.Min(720, Screen.width - 40), height = Mathf.Min(580, Screen.height - 40);
|
||||
float width = Mathf.Min(adminTab == 2 ? 940 : 720, Screen.width - 40), height = Mathf.Min(adminTab == 2 ? 680 : 580, Screen.height - 40);
|
||||
var rect = new Rect((Screen.width - width) / 2f, (Screen.height - height) / 2f, width, height);
|
||||
UiTheme.DrawShadow(rect);
|
||||
GUI.Box(rect, GUIContent.none, panel);
|
||||
@@ -338,7 +338,21 @@ namespace MSCO
|
||||
if (n > 0) mp.VehicleCheat("repaired the Satsuma (" + n + " parts)");
|
||||
}
|
||||
GUILayout.Space(6);
|
||||
if (GUILayout.Button("REFRESH", secondary, GUILayout.Height(30), GUILayout.Width(100))) VehicleAdmin.Refresh(true);
|
||||
if (GUILayout.Button("TIGHTEN ALL", secondary, GUILayout.Height(30), GUILayout.Width(110)))
|
||||
{
|
||||
int n = VehicleAdmin.SetAllBolts(true);
|
||||
Log(n + " part(s) tightened");
|
||||
if (n > 0) mp.VehicleCheat("tightened all bolts (" + n + " parts)");
|
||||
}
|
||||
GUILayout.Space(6);
|
||||
if (GUILayout.Button("LOOSEN ALL", danger, GUILayout.Height(30), GUILayout.Width(106)))
|
||||
{
|
||||
int n = VehicleAdmin.SetAllBolts(false);
|
||||
Log(n + " part(s) loosened");
|
||||
if (n > 0) mp.VehicleCheat("loosened all bolts (" + n + " parts, testing)");
|
||||
}
|
||||
GUILayout.Space(6);
|
||||
if (GUILayout.Button("REFRESH", secondary, GUILayout.Height(30), GUILayout.Width(90))) VehicleAdmin.Refresh(true);
|
||||
GUILayout.Space(12);
|
||||
GUILayout.Label("Filter", caption, GUILayout.Width(44));
|
||||
partFilter = GUILayout.TextField(partFilter ?? "", 30, field, GUILayout.Height(30));
|
||||
@@ -397,7 +411,24 @@ namespace MSCO
|
||||
GUI.DrawTexture(back, texBarBack);
|
||||
GUI.DrawTexture(new Rect(back.x, back.y, Mathf.Max(2f, back.width * frac), back.height), frac < 0.3f ? texBarLow : texBarFill);
|
||||
}
|
||||
GUILayout.Label(damaged ? "DAMAGED" : p.Wear != null ? p.Wear.Value.ToString("0") + " %" : "OK", damaged ? danger : small, GUILayout.Width(84));
|
||||
string boltText = p.Tightness != null ? (p.Bolted != null && p.Bolted.Value ? " bolted" : " loose") : "";
|
||||
GUILayout.Label((damaged ? "DAMAGED" : p.Wear != null ? p.Wear.Value.ToString("0") + " %" : "OK") + boltText, damaged ? danger : small, GUILayout.Width(120));
|
||||
if (p.HasBolts && installed)
|
||||
{
|
||||
if (GUILayout.Button("TIGHTEN", secondary, GUILayout.Height(26), GUILayout.Width(80)))
|
||||
{
|
||||
VehicleAdmin.SetBolts(p, true);
|
||||
mp.VehicleCheat("tightened " + p.Name);
|
||||
}
|
||||
GUILayout.Space(4);
|
||||
if (GUILayout.Button("LOOSEN", secondary, GUILayout.Height(26), GUILayout.Width(76)))
|
||||
{
|
||||
VehicleAdmin.SetBolts(p, false);
|
||||
mp.VehicleCheat("loosened " + p.Name);
|
||||
}
|
||||
GUILayout.Space(4);
|
||||
}
|
||||
else GUILayout.Space(164);
|
||||
if (GUILayout.Button("REPAIR", secondary, GUILayout.Height(26), GUILayout.Width(76)))
|
||||
{
|
||||
VehicleAdmin.Repair(p);
|
||||
|
||||
+114
-4
@@ -22,8 +22,14 @@ namespace MSCO
|
||||
public sealed class Part
|
||||
{
|
||||
public string Name, Category;
|
||||
public FsmBool Damaged, Installed;
|
||||
public FsmBool Damaged, Installed, Bolted;
|
||||
public FsmFloat Wear;
|
||||
// Schrauben des eingebauten Teils (BoltCheck zählt die Festigkeit, die Schrauben haben je eine Stufe 0-8)
|
||||
public PlayMakerFSM BoltCheck;
|
||||
public FsmFloat Tightness;
|
||||
public float MaxTightness;
|
||||
public readonly List<PlayMakerFSM> Bolts = new List<PlayMakerFSM>();
|
||||
public bool HasBolts { get { return Bolts.Count > 0 || Tightness != null; } }
|
||||
}
|
||||
|
||||
static readonly List<Fluid> fluids = new List<Fluid>();
|
||||
@@ -53,6 +59,7 @@ namespace MSCO
|
||||
parts.Clear();
|
||||
if (!MenuHelper.InGame) return;
|
||||
var byName = new Dictionary<string, PlayMakerFSM>();
|
||||
var partsByDb = new Dictionary<GameObject, Part>();
|
||||
foreach (PlayMakerFSM fsm in Resources.FindObjectsOfTypeAll<PlayMakerFSM>())
|
||||
{
|
||||
if (fsm == null || fsm.FsmName != "Data" || fsm.gameObject.hideFlags != HideFlags.None) continue;
|
||||
@@ -65,14 +72,17 @@ namespace MSCO
|
||||
FsmBool installed = fsm.FsmVariables.FindFsmBool("Installed");
|
||||
FsmBool damaged = fsm.FsmVariables.FindFsmBool("Damaged");
|
||||
FsmFloat wear = fsm.FsmVariables.FindFsmFloat("Wear");
|
||||
if (damaged == null && wear == null) continue;
|
||||
parts.Add(new Part
|
||||
var part = new Part
|
||||
{
|
||||
Name = Pretty(t.name),
|
||||
Category = category.Replace("Database", ""),
|
||||
Damaged = damaged, Installed = installed, Wear = wear,
|
||||
});
|
||||
Bolted = fsm.FsmVariables.FindFsmBool("Bolted"),
|
||||
};
|
||||
partsByDb[fsm.gameObject] = part;
|
||||
if (damaged != null || wear != null || part.Bolted != null) parts.Add(part);
|
||||
}
|
||||
FindBolts(partsByDb);
|
||||
parts.Sort((a, b) => string.Compare(a.Category + a.Name, b.Category + b.Name, StringComparison.Ordinal));
|
||||
|
||||
foreach (string[] def in FluidDefs)
|
||||
@@ -88,6 +98,106 @@ namespace MSCO
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Zu jedem Database-Teil das eingebaute Teil: dessen BoltCheck zeigt mit "db_ThisPart" auf den Database-Eintrag,
|
||||
/// die Schrauben (FSM "Screw") liegen darunter.
|
||||
/// </summary>
|
||||
static void FindBolts(Dictionary<GameObject, Part> partsByDb)
|
||||
{
|
||||
foreach (PlayMakerFSM fsm in UnityEngine.Object.FindObjectsOfType<PlayMakerFSM>())
|
||||
{
|
||||
if (fsm == null || fsm.FsmName != "BoltCheck") continue;
|
||||
FsmGameObject db = fsm.FsmVariables.FindFsmGameObject("db_ThisPart");
|
||||
Part part;
|
||||
if (db == null || db.Value == null || !partsByDb.TryGetValue(db.Value, out part)) continue;
|
||||
part.BoltCheck = fsm;
|
||||
part.Tightness = fsm.FsmVariables.FindFsmFloat("Tightness");
|
||||
part.MaxTightness = ClampMax(fsm);
|
||||
foreach (PlayMakerFSM bolt in fsm.GetComponentsInChildren<PlayMakerFSM>())
|
||||
if (bolt != null && bolt.FsmName == "Screw" && bolt.FsmVariables.FindFsmInt("Stage") != null) part.Bolts.Add(bolt);
|
||||
if (part.MaxTightness <= 0f) part.MaxTightness = Mathf.Max(1, part.Bolts.Count) * 8f;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Höchste Festigkeit eines Teils: das FloatClamp im BoltCheck ("Bolts OFF").</summary>
|
||||
static float ClampMax(PlayMakerFSM boltCheck)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (FsmState state in boltCheck.FsmStates)
|
||||
{
|
||||
if (!state.ActionsLoaded) state.LoadActions();
|
||||
if (state.Actions == null) continue;
|
||||
foreach (FsmStateAction a in state.Actions)
|
||||
{
|
||||
if (a == null || a.GetType().Name != "FloatClamp") continue;
|
||||
var max = a.GetType().GetField("maxValue") != null ? a.GetType().GetField("maxValue").GetValue(a) as FsmFloat : null;
|
||||
if (max != null && max.Value > 0f) return max.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
return 0f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Eingebautes Teil exakt auf seinen Halter (pivot_...) setzen - dort sitzt es im Spiel immer bei Position/Drehung 0.
|
||||
/// Nicht bei Teilen, die selbst eingedreht werden (Zündkerze, Ölfilter: Tiefe = Stufe), und nicht bei Türen/Hauben
|
||||
/// (Scharnier). Gibt true zurück, wenn es verrutscht war.
|
||||
/// </summary>
|
||||
public static bool SnapToPivot(GameObject part)
|
||||
{
|
||||
if (part == null) return false;
|
||||
Transform t = part.transform;
|
||||
if (t.parent == null || !t.parent.name.StartsWith("pivot_")) return false;
|
||||
if (part.GetComponent<HingeJoint>() != null) return false;
|
||||
foreach (PlayMakerFSM fsm in part.GetComponents<PlayMakerFSM>()) if (fsm.FsmName == "Screw") return false;
|
||||
if (t.localPosition.sqrMagnitude < 0.0004f * 0.0004f && Quaternion.Angle(t.localRotation, Quaternion.identity) < 0.05f) return false;
|
||||
t.localPosition = Vector3.zero;
|
||||
t.localRotation = Quaternion.identity;
|
||||
Rigidbody rb = part.GetComponent<Rigidbody>();
|
||||
if (rb != null && !rb.isKinematic)
|
||||
{
|
||||
rb.velocity = Vector3.zero;
|
||||
rb.angularVelocity = Vector3.zero;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>Alle Schrauben eines Teils ganz fest (true) oder ganz lose (false) - wie mit dem Werkzeug.</summary>
|
||||
public static int SetBolts(Part p, bool tight)
|
||||
{
|
||||
int changed = 0;
|
||||
foreach (PlayMakerFSM bolt in p.Bolts)
|
||||
{
|
||||
if (bolt == null || !bolt.gameObject.activeInHierarchy) continue;
|
||||
FsmInt stage = bolt.FsmVariables.FindFsmInt("Stage");
|
||||
FsmState dispatch = bolt.Fsm.GetState("Stages 2") ?? bolt.Fsm.GetState("Stages");
|
||||
if (stage == null || dispatch == null) continue;
|
||||
int target = tight ? 8 : 0;
|
||||
if (stage.Value == target) continue;
|
||||
stage.Value = target;
|
||||
FsmSync.SwitchStateSilently(bolt, dispatch); // Schraube an ihre Stelle, Zähler des Teils (Array) aktualisieren
|
||||
changed++;
|
||||
}
|
||||
if (p.Tightness != null)
|
||||
{
|
||||
float target = tight ? p.MaxTightness : 0f;
|
||||
if (Mathf.Abs(p.Tightness.Value - target) > 0.01f) { p.Tightness.Value = target; changed++; }
|
||||
}
|
||||
if (tight && p.BoltCheck != null && SnapToPivot(p.BoltCheck.gameObject)) changed++;
|
||||
return changed;
|
||||
}
|
||||
|
||||
public static int SetAllBolts(bool tight)
|
||||
{
|
||||
Refresh(true);
|
||||
int n = 0;
|
||||
foreach (Part p in parts)
|
||||
if (p.HasBolts && (p.Installed == null || p.Installed.Value) && SetBolts(p, tight) > 0) n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
/// <summary>"RadiatorHose1" -> "Radiator Hose 1", "Drumbrake_RR" -> "Drumbrake RR".</summary>
|
||||
static string Pretty(string name)
|
||||
{
|
||||
|
||||
+52
-7
@@ -64,6 +64,8 @@ namespace MSCO
|
||||
// übertragen und über die Stufen-Logik der Schraube angewendet (Position, Dichtung, Zähler des Teils)
|
||||
public FsmState BoltDispatch;
|
||||
public bool InitialSent;
|
||||
public bool Functional; // Schraube schaltet etwas (Ablassschraube): Welt-Autorität gibt den Stand einmal vor
|
||||
public bool Exact; // jede Änderung senden (Schrauben-Stufen, Festigkeit der Teile)
|
||||
}
|
||||
|
||||
readonly Dictionary<int, Var> vars = new Dictionary<int, Var>();
|
||||
@@ -122,14 +124,17 @@ namespace MSCO
|
||||
ResolveSatsuma(objects);
|
||||
foreach (Var v in vars.Values)
|
||||
{
|
||||
// Teil wird fester (eigenes Werkzeug): genau auf seinen Halter setzen (verrutschte Teile, z.B. nach der Sync)
|
||||
if (v.Exact && v.Type == 1 && v.Fsm != null && v.Fsm.FsmName == "BoltCheck" && GetFloat(v) > v.LastF + 0.01f)
|
||||
VehicleAdmin.SnapToPivot(v.Fsm.gameObject);
|
||||
// Fährt/schiebt ein anderer das Fahrzeug, ist seine Version maßgeblich - nichts senden
|
||||
int owner = objects.VehicleOwner(OwnerRoot(v.Root));
|
||||
if (owner != SyncedBody.NoOwner && owner != localId) { if (Changed(v, false)) Remember(v); continue; }
|
||||
|
||||
// Eigenes Fahrzeug: jede Änderung. Freies Fahrzeug: nur deutliche Sprünge (Öl nachfüllen, tanken ...) -
|
||||
// langsames Abdriften (z.B. Abkühlen) rechnet jeder selbst, sonst überschreiben sich alle gegenseitig
|
||||
bool big = owner == SyncedBody.NoOwner && v.BoltDispatch == null;
|
||||
if (v.BoltDispatch != null && worldAuthority && !v.InitialSent)
|
||||
bool big = owner == SyncedBody.NoOwner && !v.Exact;
|
||||
if (v.Functional && worldAuthority && !v.InitialSent)
|
||||
{
|
||||
// Einmal den eigenen Stand vorgeben, damit alle gleich sind (vorher auseinandergelaufene Schrauben)
|
||||
v.InitialSent = true;
|
||||
@@ -198,7 +203,8 @@ namespace MSCO
|
||||
if (!IsTracked(root)) { Forget(fsm); continue; }
|
||||
scanned[fsm] = fsm.transform.parent;
|
||||
Forget(fsm);
|
||||
if (RegisterFunctionalBolt(fsm, root)) continue;
|
||||
RegisterTightness(fsm, root);
|
||||
if (RegisterBolt(fsm, root)) continue;
|
||||
// FSMs, die Größen/Positionen setzen (z.B. Füllstands-Anzeigen), NICHT anfassen: ein übertragener Wert
|
||||
// kann dort eine Größe 0 ergeben - Unity stürzt dann in der Physik ab ("cleaning the mesh failed")
|
||||
if (TouchesTransform(fsm)) continue;
|
||||
@@ -223,7 +229,46 @@ namespace MSCO
|
||||
/// Leck "Oil" ist an). Sonst laufen Schrauben über FsmSync (Ereignisse): ging eins verloren, war die Ablassschraube
|
||||
/// bei einem offen und beim anderen zu - bei ihm lief dann endlos Öl aus (der Ölstand kam ja ständig nach).
|
||||
/// </summary>
|
||||
bool RegisterFunctionalBolt(PlayMakerFSM fsm, string root)
|
||||
/// <summary>
|
||||
/// Festigkeit eines Teils (BoltCheck bzw. bei aufgeschraubten Teilen wie dem Ölfilter "Use"): zählt das Werkzeug
|
||||
/// beim Schrauben hoch - beim Mitspieler drehte sich bisher nur die Schraube, das Teil blieb "lose" bzw. "fest".
|
||||
/// </summary>
|
||||
void RegisterTightness(PlayMakerFSM fsm, string root)
|
||||
{
|
||||
if (fsm.FsmName != "BoltCheck" && fsm.FsmName != "Use") return;
|
||||
FsmFloat tightness = fsm.FsmVariables.FindFsmFloat("Tightness");
|
||||
if (tightness == null) return;
|
||||
if (fsm.FsmName == "Use" && fsm.gameObject.GetComponents<PlayMakerFSM>().Length > 0)
|
||||
{
|
||||
bool screwed = false;
|
||||
foreach (PlayMakerFSM other in fsm.gameObject.GetComponents<PlayMakerFSM>()) if (other.FsmName == "Screw") screwed = true;
|
||||
if (!screwed) return;
|
||||
}
|
||||
string name = FsmSync.PathOf(fsm.transform) + "|" + fsm.FsmName + "|Tightness";
|
||||
int key = Hash(name);
|
||||
Var existing;
|
||||
if (vars.TryGetValue(key, out existing) && existing.Variable == tightness) return;
|
||||
var v = new Var { Key = key, Name = name, Root = root, Variable = tightness, Type = 1, Fsm = fsm, Exact = true };
|
||||
Remember(v);
|
||||
vars[key] = v;
|
||||
List<int> keys;
|
||||
if (!keysByFsm.TryGetValue(fsm, out keys)) keysByFsm[fsm] = keys = new List<int>();
|
||||
keys.Add(key);
|
||||
byte[] stored;
|
||||
if (pending.TryGetValue(key, out stored))
|
||||
{
|
||||
pending.Remove(key);
|
||||
byte[] value = new byte[stored.Length - 1];
|
||||
Array.Copy(stored, 1, value, 0, value.Length);
|
||||
Apply(v, stored[0], value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Jede Schraube (FSM "Screw" mit Stufe 0-8): Stufe als Zustand übertragen, angewendet über die Stufen-Logik der
|
||||
/// Schraube. Schrauben, die etwas schalten (Ablassschraube), gibt die Welt-Autorität nach dem Beitreten einmal vor.
|
||||
/// </summary>
|
||||
bool RegisterBolt(PlayMakerFSM fsm, string root)
|
||||
{
|
||||
if (fsm.FsmName != "Screw") return false;
|
||||
FsmInt stage = fsm.FsmVariables.FindFsmInt("Stage");
|
||||
@@ -243,13 +288,11 @@ namespace MSCO
|
||||
}
|
||||
}
|
||||
catch { return false; }
|
||||
if (!switches) return false;
|
||||
|
||||
string name = FsmSync.PathOf(fsm.transform) + "|" + fsm.FsmName + "|Stage";
|
||||
int key = Hash(name);
|
||||
Var existing;
|
||||
if (vars.TryGetValue(key, out existing) && existing.Variable == stage) return true;
|
||||
var v = new Var { Key = key, Name = name, Root = root, Variable = stage, Type = 2, Fsm = fsm, BoltDispatch = dispatch };
|
||||
var v = new Var { Key = key, Name = name, Root = root, Variable = stage, Type = 2, Fsm = fsm, BoltDispatch = dispatch, Functional = switches, Exact = true };
|
||||
Remember(v);
|
||||
vars[key] = v;
|
||||
List<int> keys;
|
||||
@@ -428,7 +471,9 @@ namespace MSCO
|
||||
case 1:
|
||||
float f = BitConverter.ToSingle(value, 0);
|
||||
if (float.IsNaN(f) || float.IsInfinity(f)) return; // nie ungültige Werte übernehmen
|
||||
bool tighter = v.Exact && v.Fsm != null && v.Fsm.FsmName == "BoltCheck" && f > GetFloat(v) + 0.01f;
|
||||
SetFloat(v, f);
|
||||
if (tighter) VehicleAdmin.SnapToPivot(v.Fsm.gameObject); // vom Mitspieler festgezogen: Teil auf den Halter
|
||||
break;
|
||||
case 2:
|
||||
int n = BitConverter.ToInt32(value, 0);
|
||||
|
||||
Reference in New Issue
Block a user