Admin: install parts, set time and weather; join without prompt
- VEHICLE: INSTALL for parts that are not installed - runs the game's own assembly (trigger "Assembly" like on load), so the part sits exactly on its pivot; synced to other players via FsmSync (MSCO_INSTALL) - WORLD: time buttons (2-hour steps via the sun FSM's load path) and CLEAR / RAIN / THUNDERSTORM (weather front moved above the admin); sent to everyone as mod message "msco.world" (no server update needed) - JOIN from the server browser/website connects right away in the main menu; server mods still ask before downloading Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+106
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using HutongGames.PlayMaker;
|
||||
using UnityEngine;
|
||||
@@ -30,6 +31,16 @@ namespace MSCO
|
||||
public float MaxTightness;
|
||||
public readonly List<PlayMakerFSM> Bolts = new List<PlayMakerFSM>();
|
||||
public bool HasBolts { get { return Bolts.Count > 0 || Tightness != null; } }
|
||||
// Einbau: das lose Teil (ThisPart) und der Trigger mit der FSM "Assembly" am Fahrzeug
|
||||
public FsmGameObject ThisPart, Trigger;
|
||||
public bool CanInstall
|
||||
{
|
||||
get
|
||||
{
|
||||
return Installed != null && !Installed.Value && ThisPart != null && ThisPart.Value != null
|
||||
&& Trigger != null && Trigger.Value != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static readonly List<Fluid> fluids = new List<Fluid>();
|
||||
@@ -78,6 +89,8 @@ namespace MSCO
|
||||
Category = category.Replace("Database", "").Replace("Parts", ""),
|
||||
Damaged = damaged, Installed = installed, Wear = wear,
|
||||
Bolted = fsm.FsmVariables.FindFsmBool("Bolted"),
|
||||
ThisPart = fsm.FsmVariables.FindFsmGameObject("ThisPart"),
|
||||
Trigger = fsm.FsmVariables.FindFsmGameObject("Trigger"),
|
||||
};
|
||||
partsByDb[fsm.gameObject] = part;
|
||||
if (damaged != null || wear != null || part.Bolted != null) parts.Add(part);
|
||||
@@ -229,6 +242,99 @@ namespace MSCO
|
||||
if (p.Wear != null) p.Wear.Value = 0f;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- Einbauen
|
||||
|
||||
/// <summary>
|
||||
/// Teil einbauen, wie es das Spiel beim Laden eines Spielstands macht: der Trigger am Fahrzeug bekommt das Teil
|
||||
/// (FSM "Assembly", Variable Part) und läuft durch seinen Einbau-Zustand - das setzt das Teil exakt auf seinen
|
||||
/// Halter (pivot_...), aktiviert die Schrauben und trägt es in der Database als eingebaut ein.
|
||||
/// Gibt null zurück oder den Grund, warum es nicht geht. Die anderen Spieler bauen es genauso ein.
|
||||
/// </summary>
|
||||
public static string Install(Part p)
|
||||
{
|
||||
if (!p.CanInstall) return "can't be installed";
|
||||
GameObject trigger = p.Trigger.Value, part = p.ThisPart.Value;
|
||||
if (trigger.transform.parent != null && !trigger.transform.parent.gameObject.activeInHierarchy)
|
||||
return "install the part it mounts on first";
|
||||
if (part.transform.parent != null && part.transform.parent.name == "ItemPivot") return "drop it first (it is held in a hand)";
|
||||
PlayMakerFSM assembly = Assembly(trigger);
|
||||
if (assembly == null || assembly.FsmVariables.FindFsmGameObject("Part") == null) return "no mount point found";
|
||||
if (assembly.Fsm.GetState("Check Assembly") == null && assembly.Fsm.GetState("Assemble") == null) return "no mount point found";
|
||||
|
||||
bool wasActive = trigger.activeInHierarchy;
|
||||
Run(InstallRoutine(assembly, part));
|
||||
if (wasActive) // bei den anderen Spielern genauso (der Trigger ist dort auch aktiv, solange das Teil fehlt)
|
||||
FsmSync.Outbox.Add(new FsmEventMsg
|
||||
{
|
||||
Path = FsmSync.PathOf(trigger.transform), FsmName = "Assembly", EventName = InstallEvent, State = "",
|
||||
Position = trigger.transform.position
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>Event-Name der Einbau-Nachricht an die anderen Spieler (läuft über FsmSync).</summary>
|
||||
public const string InstallEvent = "MSCO_INSTALL";
|
||||
|
||||
/// <summary>Einbau-Nachricht eines Mitspielers: zum Trigger das Teil aus der Database holen und einbauen.</summary>
|
||||
public static void InstallRemote(PlayMakerFSM assembly)
|
||||
{
|
||||
FsmGameObject db = assembly.FsmVariables.FindFsmGameObject("db_ThisPart");
|
||||
if (db == null || db.Value == null) return;
|
||||
PlayMakerFSM data = null;
|
||||
foreach (PlayMakerFSM f in db.Value.GetComponents<PlayMakerFSM>()) if (f.FsmName == "Data") data = f;
|
||||
if (data == null) return;
|
||||
FsmBool installed = data.FsmVariables.FindFsmBool("Installed");
|
||||
FsmGameObject part = data.FsmVariables.FindFsmGameObject("ThisPart");
|
||||
if (installed == null || installed.Value || part == null || part.Value == null) return;
|
||||
Run(InstallRoutine(assembly, part.Value));
|
||||
}
|
||||
|
||||
static PlayMakerFSM Assembly(GameObject trigger)
|
||||
{
|
||||
foreach (PlayMakerFSM f in trigger.GetComponents<PlayMakerFSM>()) if (f.FsmName == "Assembly") return f;
|
||||
return null;
|
||||
}
|
||||
|
||||
static IEnumerator InstallRoutine(PlayMakerFSM assembly, GameObject part)
|
||||
{
|
||||
GameObject trigger = assembly.gameObject;
|
||||
bool started = trigger.activeSelf && assembly.enabled;
|
||||
part.SetActive(true);
|
||||
trigger.SetActive(true);
|
||||
assembly.enabled = true;
|
||||
if (!started) yield return null; // FSM erst starten lassen, sonst setzt ihr Start den Zustand zurück
|
||||
if (assembly == null || part == null) yield break;
|
||||
|
||||
assembly.FsmVariables.FindFsmGameObject("Part").Value = part;
|
||||
FsmBool setup = assembly.FsmVariables.FindFsmBool("Setup");
|
||||
FsmState check = assembly.Fsm.GetState("Check Assembly");
|
||||
if (setup != null && check != null)
|
||||
{
|
||||
setup.Value = true; // wie beim Laden: "Check Assembly" sieht Setup und baut über den passenden Weg ein
|
||||
FsmSync.SwitchStateSilently(assembly, check);
|
||||
}
|
||||
else FsmSync.SwitchStateSilently(assembly, assembly.Fsm.GetState("Assemble"));
|
||||
|
||||
yield return new WaitForSeconds(0.6f);
|
||||
if (part != null) SnapToPivot(part);
|
||||
Refresh(true); // Schrauben des Teils sind jetzt aktiv
|
||||
}
|
||||
|
||||
// Coroutinen ohne eigenes MonoBehaviour im Aufrufer
|
||||
sealed class Runner : MonoBehaviour { }
|
||||
static Runner runner;
|
||||
|
||||
static void Run(IEnumerator routine)
|
||||
{
|
||||
if (runner == null)
|
||||
{
|
||||
var go = new GameObject("MSCO_AdminRunner");
|
||||
UnityEngine.Object.DontDestroyOnLoad(go);
|
||||
runner = go.AddComponent<Runner>();
|
||||
}
|
||||
runner.StartCoroutine(routine);
|
||||
}
|
||||
|
||||
public static int RepairAll()
|
||||
{
|
||||
Refresh(true);
|
||||
|
||||
Reference in New Issue
Block a user