Beta Release
This commit is contained in:
+183
@@ -0,0 +1,183 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using HutongGames.PlayMaker;
|
||||
using MSCLoader;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MSCO
|
||||
{
|
||||
/// <summary>
|
||||
/// Uhrzeit und Wetter. Ein Spieler ist "Weltuhr" (P2P: der Host; dedizierter Server: der Spieler
|
||||
/// mit der kleinsten ID) und schickt regelmäßig den Zustand der Uhr- und Wetter-FSMs
|
||||
/// (aktiver Zustand + alle Zahlen-/Ja-Nein-Variablen + Drehung, z.B. der Sonne) sowie globale
|
||||
/// Werte wie den Wochentag. Alle anderen übernehmen diesen Zustand.
|
||||
/// </summary>
|
||||
public class WorldSync
|
||||
{
|
||||
// FSMs, die Uhrzeit und Wetter steuern
|
||||
static readonly string[] TrackedFsmNames = { "Clock", "Weather" };
|
||||
// Globale PlayMaker-Variablen (Wochentag, Tageszeit)
|
||||
static readonly string[] TrackedGlobals = { "GlobalDay", "TimeOfDay" };
|
||||
|
||||
const float SendInterval = 2f;
|
||||
const float DiscoverRetry = 5f;
|
||||
|
||||
class Tracked
|
||||
{
|
||||
public string Key;
|
||||
public PlayMakerFSM Fsm;
|
||||
}
|
||||
|
||||
readonly Dictionary<string, Tracked> tracked = new Dictionary<string, Tracked>();
|
||||
float sendTimer;
|
||||
float nextDiscover;
|
||||
bool discovered;
|
||||
|
||||
public int TrackedCount { get { return tracked.Count; } }
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
tracked.Clear();
|
||||
discovered = false;
|
||||
nextDiscover = 0f;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- Senden (Weltuhr)
|
||||
|
||||
public void Update(bool isAuthority, Action<MsgType, byte[]> send, float dt)
|
||||
{
|
||||
if (!discovered && Time.time >= nextDiscover) Discover();
|
||||
if (!isAuthority || tracked.Count == 0) return;
|
||||
|
||||
sendTimer += dt;
|
||||
if (sendTimer < SendInterval) return;
|
||||
sendTimer = 0f;
|
||||
send(MsgType.WorldTime, BuildState());
|
||||
}
|
||||
|
||||
byte[] BuildState()
|
||||
{
|
||||
var alive = new List<Tracked>();
|
||||
foreach (Tracked t in tracked.Values) if (t.Fsm != null) alive.Add(t);
|
||||
|
||||
return NetSession.Build(w =>
|
||||
{
|
||||
w.Write(alive.Count);
|
||||
foreach (Tracked t in alive)
|
||||
{
|
||||
w.Write(t.Key);
|
||||
w.Write(t.Fsm.ActiveStateName ?? "");
|
||||
Quaternion rot = t.Fsm.transform.localRotation;
|
||||
w.Write(rot.x); w.Write(rot.y); w.Write(rot.z); w.Write(rot.w);
|
||||
WriteVariables(w, t.Fsm.FsmVariables, null);
|
||||
}
|
||||
WriteVariables(w, FsmVariables.GlobalVariables, TrackedGlobals);
|
||||
});
|
||||
}
|
||||
|
||||
static void WriteVariables(BinaryWriter w, FsmVariables vars, string[] only)
|
||||
{
|
||||
var floats = Filter(vars.FloatVariables, only);
|
||||
w.Write(floats.Count);
|
||||
foreach (FsmFloat v in floats) { w.Write(v.Name); w.Write(v.Value); }
|
||||
|
||||
var ints = Filter(vars.IntVariables, only);
|
||||
w.Write(ints.Count);
|
||||
foreach (FsmInt v in ints) { w.Write(v.Name); w.Write(v.Value); }
|
||||
|
||||
var bools = Filter(vars.BoolVariables, only);
|
||||
w.Write(bools.Count);
|
||||
foreach (FsmBool v in bools) { w.Write(v.Name); w.Write(v.Value); }
|
||||
}
|
||||
|
||||
static List<T> Filter<T>(T[] vars, string[] only) where T : NamedVariable
|
||||
{
|
||||
var list = new List<T>();
|
||||
if (vars == null) return list;
|
||||
foreach (T v in vars)
|
||||
if (v != null && !string.IsNullOrEmpty(v.Name) && (only == null || Array.IndexOf(only, v.Name) >= 0))
|
||||
list.Add(v);
|
||||
return list;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- Empfangen
|
||||
|
||||
public void Apply(BinaryReader r)
|
||||
{
|
||||
if (!discovered) Discover();
|
||||
|
||||
int count = r.ReadInt32();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
string key = r.ReadString();
|
||||
string state = r.ReadString();
|
||||
var rot = new Quaternion(r.ReadSingle(), r.ReadSingle(), r.ReadSingle(), r.ReadSingle());
|
||||
|
||||
Tracked t;
|
||||
PlayMakerFSM fsm = tracked.TryGetValue(key, out t) ? t.Fsm : null;
|
||||
ReadVariables(r, fsm != null ? fsm.FsmVariables : null);
|
||||
if (fsm == null) continue;
|
||||
|
||||
fsm.transform.localRotation = rot;
|
||||
if (!string.IsNullOrEmpty(state) && fsm.ActiveStateName != state)
|
||||
{
|
||||
FsmState target = fsm.Fsm.GetState(state);
|
||||
if (target != null) FsmSync.SwitchStateSilently(fsm, target); // z.B. Regen beginnt/hört auf
|
||||
}
|
||||
}
|
||||
ReadVariables(r, FsmVariables.GlobalVariables);
|
||||
}
|
||||
|
||||
static void ReadVariables(BinaryReader r, FsmVariables vars)
|
||||
{
|
||||
int floats = r.ReadInt32();
|
||||
for (int i = 0; i < floats; i++)
|
||||
{
|
||||
string name = r.ReadString();
|
||||
float value = r.ReadSingle();
|
||||
FsmFloat v = vars != null ? vars.FindFsmFloat(name) : null;
|
||||
if (v != null) v.Value = value;
|
||||
}
|
||||
int ints = r.ReadInt32();
|
||||
for (int i = 0; i < ints; i++)
|
||||
{
|
||||
string name = r.ReadString();
|
||||
int value = r.ReadInt32();
|
||||
FsmInt v = vars != null ? vars.FindFsmInt(name) : null;
|
||||
if (v != null) v.Value = value;
|
||||
}
|
||||
int bools = r.ReadInt32();
|
||||
for (int i = 0; i < bools; i++)
|
||||
{
|
||||
string name = r.ReadString();
|
||||
bool value = r.ReadBoolean();
|
||||
FsmBool v = vars != null ? vars.FindFsmBool(name) : null;
|
||||
if (v != null) v.Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- Suchen
|
||||
|
||||
void Discover()
|
||||
{
|
||||
nextDiscover = Time.time + DiscoverRetry;
|
||||
tracked.Clear();
|
||||
foreach (PlayMakerFSM fsm in SceneCache.Fsms(5f))
|
||||
{
|
||||
if (fsm == null) continue;
|
||||
if (Array.IndexOf(TrackedFsmNames, fsm.FsmName) < 0) continue;
|
||||
string root = fsm.transform.root.name;
|
||||
if (root == "PLAYER" || root.StartsWith("MSCO_")) continue;
|
||||
|
||||
string key = FsmSync.PathOf(fsm.transform) + "|" + fsm.FsmName;
|
||||
if (!tracked.ContainsKey(key)) tracked[key] = new Tracked { Key = key, Fsm = fsm };
|
||||
}
|
||||
if (tracked.Count == 0) return; // Welt noch nicht fertig geladen - später nochmal
|
||||
discovered = true;
|
||||
ModConsole.Print("[MSCO] Time/weather sync: " + tracked.Count + " FSMs");
|
||||
if (FsmSync.Debug)
|
||||
foreach (string key in tracked.Keys) ModConsole.Print("[MSCO] " + key);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user