MSCO 2.10.2: passenger only while moving, drain plug sync, admin VEHICLE tab, profile layout
- Passenger: auto ride-along only when the vehicle moves (speed from its motion, also for kinematic remote cars) - no more getting stuck while working in the engine bay or re-captured - Bolts with a function (drain plug: stage 0-5 = oil leak on) are synced as stage and applied through the bolt's own stage logic; world authority sends its state once after joining. Fixes endless oil leaking when players had the drain plug in different states - Admin menu VEHICLE tab: fluids with FILL/EMPTY, all Database parts with wear/damage, REPAIR/BREAK per part, REPAIR ALL, filter - Server profile: info and players as two equal cards, no wrapping - fsmdump also lists FSM variables Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+137
@@ -0,0 +1,137 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using HutongGames.PlayMaker;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MSCO
|
||||
{
|
||||
/// <summary>
|
||||
/// Admin-Menü, Reiter VEHICLE: Füllstände und Teile des Satsuma aus der "Database" des Spiels anzeigen und zum Testen
|
||||
/// reparieren/zerstören. Jedes Teil hat dort ein Objekt mit der FSM "Data" (Installed, Bolted, Damaged, teils Wear);
|
||||
/// die Füllstände stehen in Tank, Ölwanne, Brems- und Kupplungszylinder. Die Werte überträgt VehicleStateSync an alle.
|
||||
/// </summary>
|
||||
public static class VehicleAdmin
|
||||
{
|
||||
public sealed class Fluid
|
||||
{
|
||||
public string Label;
|
||||
public FsmFloat Value;
|
||||
public float Max;
|
||||
}
|
||||
|
||||
public sealed class Part
|
||||
{
|
||||
public string Name, Category;
|
||||
public FsmBool Damaged, Installed;
|
||||
public FsmFloat Wear;
|
||||
}
|
||||
|
||||
static readonly List<Fluid> fluids = new List<Fluid>();
|
||||
static readonly List<Part> parts = new List<Part>();
|
||||
static float scannedAt = -100f;
|
||||
|
||||
public static List<Fluid> Fluids { get { Refresh(false); return fluids; } }
|
||||
public static List<Part> Parts { get { Refresh(false); return parts; } }
|
||||
|
||||
// Füllstand: Teil in der Database, Variable, Anzeige, Maximum (Tank: aus MaxCapacity)
|
||||
static readonly string[][] FluidDefs =
|
||||
{
|
||||
new[] { "FuelTank", "FuelLevel", "Fuel", "36" },
|
||||
new[] { "Oilpan", "Oil", "Engine oil", "3" },
|
||||
new[] { "BrakeMasterCylinder", "BrakeFluidF", "Brake fluid (front)", "1" },
|
||||
new[] { "BrakeMasterCylinder", "BrakeFluidR", "Brake fluid (rear)", "1" },
|
||||
new[] { "ClutchMasterCylinder", "ClutchFluid", "Clutch fluid", "0.5" },
|
||||
new[] { "Radiator", "Water", "Coolant", "6" },
|
||||
};
|
||||
|
||||
/// <summary>Database neu einlesen (höchstens alle 5 s, außer erzwungen).</summary>
|
||||
public static void Refresh(bool force)
|
||||
{
|
||||
if (!force && Time.realtimeSinceStartup - scannedAt < 5f) return;
|
||||
scannedAt = Time.realtimeSinceStartup;
|
||||
fluids.Clear();
|
||||
parts.Clear();
|
||||
if (!MenuHelper.InGame) return;
|
||||
var byName = new Dictionary<string, PlayMakerFSM>();
|
||||
foreach (PlayMakerFSM fsm in Resources.FindObjectsOfTypeAll<PlayMakerFSM>())
|
||||
{
|
||||
if (fsm == null || fsm.FsmName != "Data" || fsm.gameObject.hideFlags != HideFlags.None) continue;
|
||||
Transform t = fsm.transform;
|
||||
if (t.root.name != "Database" || t.parent == null || t.parent.parent != t.root) continue;
|
||||
string category = t.parent.name;
|
||||
if (category == "DatabaseOrders" || category == "PlayerDatabase") continue; // Bestellungen/Spieler: keine Fahrzeugteile
|
||||
byName[t.name] = fsm;
|
||||
|
||||
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
|
||||
{
|
||||
Name = Pretty(t.name),
|
||||
Category = category.Replace("Database", ""),
|
||||
Damaged = damaged, Installed = installed, Wear = wear,
|
||||
});
|
||||
}
|
||||
parts.Sort((a, b) => string.Compare(a.Category + a.Name, b.Category + b.Name, StringComparison.Ordinal));
|
||||
|
||||
foreach (string[] def in FluidDefs)
|
||||
{
|
||||
PlayMakerFSM fsm;
|
||||
if (!byName.TryGetValue(def[0], out fsm)) continue;
|
||||
FsmFloat value = fsm.FsmVariables.FindFsmFloat(def[1]);
|
||||
if (value == null) continue;
|
||||
float max = float.Parse(def[3], System.Globalization.CultureInfo.InvariantCulture);
|
||||
FsmFloat capacity = fsm.FsmVariables.FindFsmFloat("MaxCapacity");
|
||||
if (def[0] == "FuelTank" && capacity != null && capacity.Value > 0f) max = capacity.Value;
|
||||
fluids.Add(new Fluid { Label = def[2], Value = value, Max = max });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>"RadiatorHose1" -> "Radiator Hose 1", "Drumbrake_RR" -> "Drumbrake RR".</summary>
|
||||
static string Pretty(string name)
|
||||
{
|
||||
var sb = new System.Text.StringBuilder();
|
||||
for (int i = 0; i < name.Length; i++)
|
||||
{
|
||||
char c = name[i];
|
||||
if (c == '_') { sb.Append(' '); continue; }
|
||||
if (i > 0 && ((char.IsUpper(c) && char.IsLower(name[i - 1])) || (char.IsDigit(c) && !char.IsDigit(name[i - 1])))) sb.Append(' ');
|
||||
sb.Append(c);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static void SetFluid(Fluid f, bool full)
|
||||
{
|
||||
if (f.Value != null) f.Value.Value = full ? f.Max : 0f;
|
||||
}
|
||||
|
||||
public static void Repair(Part p)
|
||||
{
|
||||
if (p.Damaged != null) p.Damaged.Value = false;
|
||||
if (p.Wear != null) p.Wear.Value = 100f;
|
||||
}
|
||||
|
||||
public static void Break(Part p)
|
||||
{
|
||||
if (p.Damaged != null) p.Damaged.Value = true;
|
||||
if (p.Wear != null) p.Wear.Value = 0f;
|
||||
}
|
||||
|
||||
public static int RepairAll()
|
||||
{
|
||||
Refresh(true);
|
||||
int n = 0;
|
||||
foreach (Part p in parts)
|
||||
{
|
||||
if (p.Installed != null && !p.Installed.Value) continue;
|
||||
bool needs = (p.Damaged != null && p.Damaged.Value) || (p.Wear != null && p.Wear.Value < 100f);
|
||||
if (!needs) continue;
|
||||
Repair(p);
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user