Decompiled source of RandomTerrainEnhance v1.0.20
RandomTerrainEnhance.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using PeakCompatibility; using PeakGameMeters; using Photon.Pun; using Photon.Realtime; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UIElements; using Zorro.Core; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("AiAe")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.20.0")] [assembly: AssemblyInformationalVersion("1.0.20+beb91238582d60e31105455f250d7a12bd6a2262")] [assembly: AssemblyProduct("RandomTerrainEnhance")] [assembly: AssemblyTitle("RandomTerrainEnhance")] [assembly: AssemblyVersion("1.0.20.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace PeakGameMeters { internal static class GameMeterMigration { internal const string Marker = "# PEAK game-metre migration v1 completed"; internal static string UpgradeText(string text, float scale, Func<string, string, bool> matches) { if (text.Contains("# PEAK game-metre migration v1 completed")) { return text; } if (float.IsNaN(scale) || float.IsInfinity(scale) || scale <= 0f) { throw new InvalidOperationException("Invalid PEAK unitsToMeters."); } string text2 = string.Empty; string text3 = Regex.Match(text, "\\r\\n|\\n|\\r").Value; if (text3.Length == 0) { text3 = Environment.NewLine; } StringBuilder stringBuilder = new StringBuilder("# PEAK game-metre migration v1 completed" + text3); foreach (Match item in Regex.Matches(text, "[^\\r\\n]*(?:\\r\\n|\\n|\\r|$)")) { if (item.Length == 0) { continue; } string text4 = item.Value; string text5 = text4.Trim(); if (text5.StartsWith("[", StringComparison.Ordinal) && text5.EndsWith("]", StringComparison.Ordinal)) { text2 = text5.Substring(1, text5.Length - 2).Trim(); } int num = text4.IndexOf('='); if (num >= 0 && !text5.StartsWith("#", StringComparison.Ordinal) && !text5.StartsWith(";", StringComparison.Ordinal) && matches(text2, text4.Substring(0, num).Trim())) { if (!float.TryParse(text4.Substring(num + 1).Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || float.IsNaN(result) || float.IsInfinity(result)) { throw new FormatException("Invalid legacy distance in section " + text2 + "; migration aborted."); } float f = result * scale; if (float.IsNaN(f) || float.IsInfinity(f)) { throw new FormatException("Legacy distance overflow; migration aborted."); } string value = Regex.Match(text4, "(?:\\r\\n|\\n|\\r)$").Value; text4 = text4.Substring(0, num + 1) + " " + f.ToString("R", CultureInfo.InvariantCulture) + value; } stringBuilder.Append(text4); } return stringBuilder.ToString(); } internal static void Upgrade(ConfigFile config, float scale, Func<string, string, bool> matches) { string configFilePath = config.ConfigFilePath; string text = configFilePath + ".game-meters-v1"; if (File.Exists(text)) { if (File.ReadAllText(text).Trim() != "# PEAK game-metre migration v1 completed") { throw new IOException("Invalid game-metre migration record: " + text); } return; } bool saveOnConfigSet = config.SaveOnConfigSet; config.SaveOnConfigSet = false; try { if (File.Exists(configFilePath)) { string text2 = File.ReadAllText(configFilePath); string text3 = UpgradeText(text2, scale, matches); if (text3 != text2) { string text4 = configFilePath + "." + Guid.NewGuid().ToString("N") + ".tmp"; string destinationBackupFileName = configFilePath + ".unity-units-" + DateTime.UtcNow.ToString("yyyyMMddHHmmssfffffff", CultureInfo.InvariantCulture) + ".bak"; try { File.WriteAllText(text4, text3, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); File.Replace(text4, configFilePath, destinationBackupFileName); } finally { if (File.Exists(text4)) { File.Delete(text4); } } } } Directory.CreateDirectory(Path.GetDirectoryName(configFilePath)); string text5 = text + "." + Guid.NewGuid().ToString("N") + ".tmp"; try { File.WriteAllText(text5, "# PEAK game-metre migration v1 completed", new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); File.Move(text5, text); } finally { if (File.Exists(text5)) { File.Delete(text5); } } if (File.Exists(configFilePath)) { config.Reload(); } } finally { config.SaveOnConfigSet = saveOnConfigSet; } } } } namespace PeakCompatibility { internal static class CampfireCleanupGuard { private const string IteratorName = "ShowNextSegmentCoroutine"; private const string CleanupListFieldName = "viewsToDestoryIfNotAlreadyWhenSwitchingSegments"; private static FieldInfo? _cleanupListField; private static Func<bool>? _enabled; private static Action<string>? _log; private static Action<PhotonView> _nextDestroy = PhotonNetwork.Destroy; private static bool _installed; private static bool _errorLogged; private static readonly HashSet<int> LoggedViews = new HashSet<int>(); internal static string State { get; private set; } = "Not installed"; internal static void Install(Harmony harmony, Func<bool> enabled, Action<string> log) { //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Expected O, but got Unknown if (_installed) { return; } _enabled = enabled; _log = log; try { _cleanupListField = AccessTools.Field(typeof(MapHandler), "viewsToDestoryIfNotAlreadyWhenSwitchingSegments"); List<MethodInfo> list = new List<MethodInfo>(); FindIteratorMoveNext(typeof(MapHandler), list); if (_cleanupListField == null || list.Count != 1) { State = "Skipped: segment cleanup target not uniquely identified"; log("[CampfireCleanup] " + State); return; } MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(PhotonNetwork), "Destroy", new Type[1] { typeof(PhotonView) }, (Type[])null); MethodInfo methodInfo2 = AccessTools.DeclaredMethod(typeof(CampfireCleanupGuard), "DestroyUnlessProtected", (Type[])null, (Type[])null); MethodInfo methodInfo3 = AccessTools.DeclaredMethod(typeof(CampfireCleanupGuard), "Transpile", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null || methodInfo3 == null) { State = "Skipped: Photon destroy signature changed"; log("[CampfireCleanup] " + State); return; } harmony.Patch((MethodBase)list[0], (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo3), (HarmonyMethod)null, (HarmonyMethod)null); _installed = true; if (State == "Installed") { log("[CampfireCleanup] Installed component/root guard for segment item cleanup (not ViewID 55)."); } } catch (Exception ex) { State = "Install failed"; log("[CampfireCleanup] " + State + ": " + ex.Message); } } private static void FindIteratorMoveNext(Type parent, List<MethodInfo> candidates) { Type[] nestedTypes = parent.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic); foreach (Type type in nestedTypes) { if (type.Name.IndexOf("ShowNextSegmentCoroutine", StringComparison.Ordinal) >= 0) { MethodInfo methodInfo = AccessTools.DeclaredMethod(type, "MoveNext", (Type[])null, (Type[])null); if (methodInfo != null && methodInfo.ReturnType == typeof(bool)) { candidates.Add(methodInfo); } } FindIteratorMoveNext(type, candidates); } } private static IEnumerable<CodeInstruction> Transpile(IEnumerable<CodeInstruction> instructions) { AccessTools.DeclaredMethod(typeof(PhotonNetwork), "Destroy", new Type[1] { typeof(PhotonView) }, (Type[])null); MethodInfo operand = AccessTools.DeclaredMethod(typeof(CampfireCleanupGuard), "DestroyUnlessProtected", (Type[])null, (Type[])null); List<CodeInstruction> list = instructions.ToList(); List<CodeInstruction> list2 = list.Where(IsDestroyChainCall).ToList(); if (list2.Count != 1 || list.All((CodeInstruction i) => !(i.operand is FieldInfo fieldInfo) || !(fieldInfo.Name == "viewsToDestoryIfNotAlreadyWhenSwitchingSegments"))) { State = "Skipped: unexpected segment-cleanup IL"; _log?.Invoke("[CampfireCleanup] " + State); return list; } if (!(list2[0].operand is MethodInfo methodInfo)) { return list; } _nextDestroy = (Action<PhotonView>)methodInfo.CreateDelegate(typeof(Action<PhotonView>)); list2[0].operand = operand; State = "Installed"; return list; } private static bool IsDestroyChainCall(CodeInstruction instruction) { MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(PhotonNetwork), "Destroy", new Type[1] { typeof(PhotonView) }, (Type[])null); if (CodeInstructionExtensions.Calls(instruction, methodInfo)) { return true; } if (!(instruction.operand is MethodInfo methodInfo2) || methodInfo2.Name != "DestroyUnlessProtected") { return false; } string text = methodInfo2.DeclaringType?.FullName; if (methodInfo2 != AccessTools.DeclaredMethod(typeof(CampfireCleanupGuard), "DestroyUnlessProtected", (Type[])null, (Type[])null) && methodInfo2.IsStatic && methodInfo2.ReturnType == typeof(void) && methodInfo2.GetParameters().Length == 1 && methodInfo2.GetParameters()[0].ParameterType == typeof(PhotonView) && text == typeof(CampfireCleanupGuard).FullName) { if (!(methodInfo2.Module.Assembly.GetName().Name == "RandomTerrainEnhance")) { return methodInfo2.Module.Assembly.GetName().Name == "TerrainCustomiser"; } return true; } return false; } private static void DestroyUnlessProtected(PhotonView view) { if (!TryProtectRegisteredKilnCampfire(view)) { _nextDestroy(view); } } private static bool TryProtectRegisteredKilnCampfire(PhotonView view) { try { if (_enabled == null || !_enabled() || (Object)(object)view == (Object)null) { return false; } MapHandler instance = Singleton<MapHandler>.Instance; if ((Object)(object)instance == (Object)null || !IsRegisteredKilnCampfire(instance.segments, view)) { return false; } if (LoggedViews.Add(((Object)view).GetInstanceID())) { _log?.Invoke("[CampfireCleanup] Preserved registered Kiln campfire in segment cleanup; ViewID=" + view.ViewID + "."); } return true; } catch (Exception ex) { if (!_errorLogged) { _errorLogged = true; _log?.Invoke("[CampfireCleanup] Check failed; keeping vanilla destroy: " + ex.Message); } return false; } } private static bool IsRegisteredKilnCampfire(MapSegment[]? segments, PhotonView view) { if (segments == null || (Object)(object)view == (Object)null) { return false; } Campfire component = ((Component)view).GetComponent<Campfire>(); if ((Object)(object)component == (Object)null || ((Object)component).name.IndexOf("Kiln", StringComparison.OrdinalIgnoreCase) < 0) { return false; } Transform transform = ((Component)view).transform; Transform transform2 = ((Component)component).transform; foreach (MapSegment val in segments) { if (val != null && !((Object)(object)val.segmentCampfire == (Object)null)) { Transform transform3 = val.segmentCampfire.transform; if (((Object)(object)transform == (Object)(object)transform3 || transform.IsChildOf(transform3)) && ((Object)(object)transform2 == (Object)(object)transform3 || transform2.IsChildOf(transform3))) { return true; } } } return false; } internal static void ResetScene() { LoggedViews.Clear(); } } internal static class GeneratedMapScope { private static WeakReference _map = new WeakReference(null); internal static void Mark(object handler) { _map = new WeakReference(handler); } internal static bool IsCurrent(object handler) { object target = _map.Target; if (handler != null && target != null) { return target == handler; } return false; } internal static void Clear() { _map = new WeakReference(null); } } } namespace RandomTerrainEnhance { public static class Arbiter { public const string TFA_GUID = "com.CptPICHU.peak.truefinalascent"; private static Type _tFinalAscent; private static Type _tRoom; private static Type _tTrStepAside; private static PropertyInfo _pActive; private static FieldInfo _fActiveBacking; private static FieldInfo _fWeTurnedItOff; private static MethodInfo _mComeBack; private static bool _restoreToasted; public static string TfaVersion { get; private set; } public static bool TfaLoaded => TfaVersion != null; private static bool FixEnabled { get { if (Plugin.EnableTfaFix != null) { return Plugin.EnableTfaFix.Value; } return true; } } public static void Detect() { if (!Chainloader.PluginInfos.TryGetValue("com.CptPICHU.peak.truefinalascent", out var value)) { TfaVersion = null; return; } TfaVersion = value.Metadata.Version.ToString(); _tFinalAscent = AccessTools.TypeByName("TrueFinalAscent.FinalAscent"); _tRoom = AccessTools.TypeByName("TrueFinalAscent.FinalAscentRoom"); _tTrStepAside = AccessTools.TypeByName("TrueFinalAscent.FinalAscentTerrainRandomiser"); if (_tFinalAscent != null) { _pActive = AccessTools.Property(_tFinalAscent, "Active"); _fActiveBacking = AccessTools.Field(_tFinalAscent, "<Active>k__BackingField"); } if (_tTrStepAside != null) { _fWeTurnedItOff = AccessTools.Field(_tTrStepAside, "_weTurnedItOff"); _mComeBack = AccessTools.Method(_tTrStepAside, "ComeBack", (Type[])null, (Type[])null); } Plugin.Log.LogInfo((object)("[地形增强] 检测到 TrueFinalAscent v" + TfaVersion + ",仲裁层已启用" + $"(Active={_pActive != null || _fActiveBacking != null} ComeBack={_mComeBack != null})")); } public static bool FaActive() { try { if (_pActive != null) { return (bool)_pActive.GetValue(null); } if (_fActiveBacking != null) { return (bool)_fActiveBacking.GetValue(null); } } catch { } return false; } public static bool FaRoomFlag() { if (!PhotonNetwork.InRoom) { return false; } Hashtable customProperties = ((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties; bool flag = default(bool); int num; if (customProperties != null && ((Dictionary<object, object>)(object)customProperties).TryGetValue((object)"FA", out object value)) { if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } public static bool FaRun() { if (!FaActive()) { return FaRoomFlag(); } return true; } public static bool Allows(ITerrainTarget t, Cap cap) { if (cap == Cap.Sync || cap == Cap.Bake) { return true; } if (!FaRun()) { return true; } if (t != null && t.State.OffReason == null) { t.State.OffReason = Loc.T("Final Ascent run (TrueFinalAscent)", "Final Ascent 局(TrueFinalAscent 接管地形)"); } return false; } public static void OnGenerationBegin(ITerrainTarget t) { try { if (FixEnabled && PhotonNetwork.InRoom && FaRoomFlag() && t != null && t.IsRunActive()) { if (PhotonNetwork.IsMasterClient) { ClearStaleFaKeys(t.NameZh + " 正在生成本局地形"); return; } t.State.OffReason = Loc.T("stale Final Ascent room flag detected", "检测到上一局 Final Ascent 的残留房间标记"); Gui.AddToast(Loc.T("[RandomTerrainEnhance] Stale Final Ascent room flag detected while " + t.NameEn + " is generating. Terrain may differ and TrueFinalAscent may pull you to the ground; ask the host to restart the lobby.", "[随机地形增强] 检测到上一局 Final Ascent 的残留房间标记,而本局地形由" + t.NameZh + "生成。地形可能不一致、TrueFinalAscent 可能把你往地面拖拽;建议让主机重建房间。")); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[地形增强] FA 残留检查异常: " + ex.Message)); } } public static void ClearStaleFaKeys(string why) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown if (!FixEnabled || !PhotonNetwork.InRoom || !PhotonNetwork.IsMasterClient) { return; } try { Hashtable customProperties = ((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties; if (customProperties == null) { return; } Hashtable val = new Hashtable(); foreach (object key in ((Dictionary<object, object>)(object)customProperties).Keys) { if (key is string text && text.StartsWith("FA", StringComparison.Ordinal)) { val[(object)text] = null; } } if (((Dictionary<object, object>)(object)val).Count != 0) { PhotonNetwork.CurrentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null); Plugin.Log.LogWarning((object)string.Format("{0} 已清理 {1} 个残留的 Final Ascent 房间属性({2})", "[地形增强]", ((Dictionary<object, object>)(object)val).Count, why)); Gui.AddToast(Loc.T(string.Format("[{0}] Cleared {1} stale Final Ascent room flag(s)", "RandomTerrainEnhance", ((Dictionary<object, object>)(object)val).Count), string.Format("[{0}] 已清理 {1} 个残留的 Final Ascent 房间标记", "随机地形增强", ((Dictionary<object, object>)(object)val).Count))); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[地形增强] 清理残留 FA 键失败: " + ex.Message)); } } public static void AirportTick() { if (!TfaLoaded || _mComeBack == null || _fWeTurnedItOff == null) { return; } if (!Plugin.InAirport()) { _restoreToasted = false; } else { if (FaRun()) { return; } try { object value = _fWeTurnedItOff.GetValue(null); if (value is bool && (bool)value) { _mComeBack.Invoke(null, null); Plugin.Log.LogWarning((object)"[地形增强] 已替 TrueFinalAscent 还原地形随机器开关(它在局末不会自己还原)"); if (!_restoreToasted) { _restoreToasted = true; Gui.AddToast(Loc.T("[RandomTerrainEnhance] Restored TerrainRandomiser's switch that TrueFinalAscent left turned off", "[随机地形增强] 已还原被 TrueFinalAscent 关掉且未复原的地形随机器开关")); } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[地形增强] 还原地形随机器开关失败: " + ex.Message)); } } } } public static class GenFixes { [HarmonyPatch(typeof(MapHandler), "InitializeMap")] internal static class MapInitPatch { private static object _cachedSettings; private static int _cachedSeed; private static bool DropLobbyStaleSettings(TrTarget tr) { try { if (!PhotonNetwork.InRoom) { return false; } if (PhotonNetwork.IsMasterClient) { return false; } if (!tr.LocalWantsRandom()) { return false; } string text = tr.RoomMapSettingsJson(); if (!string.IsNullOrEmpty(text) && EnableRandomiserInJson(text)) { return false; } Player masterClient = PhotonNetwork.MasterClient; if (masterClient != null && RoomWatch.WithinGrace(masterClient) && string.IsNullOrEmpty(text)) { return false; } tr.ClearRoomMapSettings(); Plugin.Log.LogWarning((object)"[地形增强] 房主本局未启用随机地形,本机检测到来自 Steam 大厅的残留随机配置,已清除并跟随房主走原版地形(房主权威)"); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("[地形增强] 大厅脏数据检查异常: " + ex.Message)); return false; } } private static bool EnableRandomiserInJson(string json) { try { Match match = Regex.Match(json, "\"enableRandomiser\"\\s*:\\s*(true|false)"); return match.Success && match.Groups[1].Value == "true"; } catch { return false; } } private static bool GuardUnsupportedScene(TrTarget tr) { try { if (!tr.LocalWantsRandom()) { return false; } if (tr.CurrentSceneSupportsTr()) { return false; } tr.ClearRoomMapSettings(); Plugin.Log.LogWarning((object)"[地形增强] 当前场景缺少地形随机器所需结构(非 WilIsland 类,如 Level_x),已屏蔽随机配置改走原版,避免 TR 空引用导致地图不生成/掉虚空"); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("[地形增强] 非常规场景守卫异常: " + ex.Message)); return false; } } private static void EnsureRoomSettings(TrTarget tr) { try { object roomMapSettingsRaw = tr.GetRoomMapSettingsRaw(); if (roomMapSettingsRaw != null) { _cachedSettings = roomMapSettingsRaw; _cachedSeed = tr.SeedOf(roomMapSettingsRaw); SameRunReload = false; } else { if (_cachedSettings == null) { return; } string text = tr.RoomMapSettingsJson(); if (!string.IsNullOrEmpty(text)) { int num = SeedOfJson(text); if (num != 0 && num == _cachedSeed) { tr.SetRoomMapSettingsRaw(_cachedSettings); SameRunReload = true; Plugin.Log.LogInfo((object)string.Format("{0} 二次加载检测到地形随机器配置已被清空,已回补本局配置(seed={1}),使本次生成仍走随机地形而非原版", "[地形增强]", num)); } } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[地形增强] 回补地形随机器配置失败: " + ex.Message)); } } private static bool DropForCustomMap(TrTarget tr) { if (!TcSession.OwnsMap()) { return false; } _cachedSettings = null; _cachedSeed = 0; SameRunReload = false; GeneratedMapScope.Clear(); tr.State.HasLocked = false; tr.State.InGeneration = false; tr.State.FixActive = false; tr.State.ViewFixActive = false; tr.State.OffReason = null; ViewFix.Reset(); SyncCheck.OnForeignMap(); if (tr.GetRoomMapSettingsRaw() != null) { tr.ClearRoomMapSettings(); Plugin.Log.LogInfo((object)"[地形增强] 本局是地形定制器自定义图:已清掉本机地形随机器的残留配置,不生成随机图"); } return true; } private static int SeedOfJson(string json) { try { Match match = Regex.Match(json, "\"seed\"\\s*:\\s*(-?\\d+)"); int result; return (match.Success && int.TryParse(match.Groups[1].Value, out result)) ? result : 0; } catch { return 0; } } [HarmonyPrefix] [HarmonyPriority(700)] private static void Pre(out bool __state) { __state = false; try { Plugin.ApplyHostBake(force: true); TrTarget tR = Targets.TR; if (tR.Version == null || DropForCustomMap(tR) || DropLobbyStaleSettings(tR) || GuardUnsupportedScene(tR)) { return; } EnsureRoomSettings(tR); if (!tR.IsRunActive() || InitDone()) { return; } SyncCheck.OnGenerationBegin(tR); ViewFix.Reset(); Targets.BeginRunFor(tR); tR.State.Seed = tR.GetSeed(); Arbiter.OnGenerationBegin(tR); bool flag = Negotiate.Decide(tR, Cap.Rng); bool flag2 = Negotiate.Decide(tR, Cap.ViewId); if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient) { Plugin.GenLock? genLock = Negotiate.GetGenLock(tR); if (genLock.HasValue && genLock.Value.Seed == tR.State.Seed && Negotiate.HostPatch() != Tri.No && Arbiter.Allows(tR, Cap.Rng)) { flag = genLock.Value.Fix; flag2 = genLock.Value.Vf; } } tR.State.FixActive = flag; tR.State.ViewFixActive = flag2; tR.State.HasLocked = true; GeneratedMapScope.Mark(Singleton<MapHandler>.Instance); __state = true; if (PhotonNetwork.IsMasterClient || !PhotonNetwork.InRoom) { BroadcastGenLock(tR); } Plugin.Log.LogInfo((object)("[地形增强] 地形随机器生成开始: 随机流隔离=" + (flag ? "启用" : "关闭") + " " + string.Format("ViewID对齐={0} seed={1}", flag2 ? "启用" : "关闭", tR.State.Seed) + ((tR.State.OffReason == null) ? "" : ("(" + tR.State.OffReason + ")")))); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[地形增强] 生成开始处理异常: " + ex.Message)); } } [HarmonyPostfix] [HarmonyPriority(0)] private static void Post(bool __state) { TrTarget tR = Targets.TR; if (__state && InitDone()) { tR.State.InGeneration = false; SyncCheck.OnGenerationEnd(tR); } } } [HarmonyPatch(typeof(PropSpawner), "ExecuteImmediately")] private static class PropSpawnerIsolate { [HarmonyPrefix] [HarmonyPriority(700)] private static void Pre(PropSpawner __instance, out State? __state) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) __state = null; ITerrainTarget terrainTarget = IsolatingTarget(); if (terrainTarget != null && !((Object)(object)__instance == (Object)null)) { __state = Random.state; Random.InitState(PathSeed(((Component)__instance).transform, terrainTarget.State.Seed)); } } [HarmonyPostfix] [HarmonyPriority(0)] private static void Post(State? __state) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) if (__state.HasValue) { Random.state = __state.Value; } } } private static string _pendingLock; private static ITerrainTarget _pendingLockTarget; private static readonly FieldRef<MapHandler, bool> _initDone = AccessTools.FieldRefAccess<MapHandler, bool>("hasFinishedStartRoutine"); public static bool SameRunReload { get; private set; } public static bool FixActive => Targets.TR.State.FixActive; public static bool HasLocked => Targets.TR.State.HasLocked; public static bool? GetRoomFix() { return Negotiate.GetRoomBool(Targets.TR.Keys.Fix); } public static int TryGetSeed() { return Targets.TR.GetSeed(); } private static bool InitDone() { try { MapHandler instance = Singleton<MapHandler>.Instance; return (Object)(object)instance != (Object)null && _initDone.Invoke(instance); } catch { return false; } } private static void BroadcastGenLock(ITerrainTarget t) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown //IL_00b8: Expected O, but got Unknown _pendingLock = null; _pendingLockTarget = null; bool? localBake = Plugin.GetLocalBake(); string text = string.Format("{0}|{1}|", t.State.Seed, (!localBake.HasValue) ? "?" : (localBake.Value ? "1" : "0")) + (t.State.FixActive ? "1" : "0") + "|" + (t.State.ViewFixActive ? "1" : "0"); if (PhotonNetwork.InRoom) { Room currentRoom = PhotonNetwork.CurrentRoom; Hashtable val = new Hashtable(); ((Dictionary<object, object>)val).Add((object)t.Keys.GenLock, (object)text); currentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null); } else { _pendingLock = text; _pendingLockTarget = t; } } public static void FlushPendingLock() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_0049: Expected O, but got Unknown if (_pendingLock != null && _pendingLockTarget != null && PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient) { Room currentRoom = PhotonNetwork.CurrentRoom; Hashtable val = new Hashtable(); ((Dictionary<object, object>)val).Add((object)_pendingLockTarget.Keys.GenLock, (object)_pendingLock); currentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null); Plugin.Log.LogInfo((object)("[地形增强] 已补发生成锁定 (QuickLoad): " + _pendingLock)); _pendingLock = null; _pendingLockTarget = null; } } private static ITerrainTarget IsolatingTarget() { ITerrainTarget[] all = Targets.All; foreach (ITerrainTarget terrainTarget in all) { if (terrainTarget.Version != null) { TargetState state = terrainTarget.State; if (state.FixActive && state.InGeneration) { return terrainTarget; } } } return null; } private static int PathSeed(Transform t, int runSeed) { int num = -2128831035; while ((Object)(object)t != (Object)null) { string name = ((Object)t).name; foreach (char c in name) { num = (num ^ c) * 16777619; } num = (num ^ t.GetSiblingIndex()) * 16777619; t = t.parent; } return num ^ (runSeed * 486187739); } } public class GuiHost : MonoBehaviour { private void OnGUI() { Gui.Draw(); } } public static class Gui { private class Toast { public string Msg; public float Until; } private struct Cell { public string Text; public Color Color; public Cell(string t, Color c) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) Text = t; Color = c; } } [CompilerGenerated] private static class <>O { public static WindowFunction <0>__DrawDetailWindow; public static WindowFunction <1>__DrawMainWindow; } public static bool ShowPanel; public static bool ShowDetail; private static readonly Color ColGreen = new Color(0.56f, 0.75f, 0.56f); private static readonly Color ColRed = new Color(0.79f, 0.51f, 0.51f); private static readonly Color ColGray = new Color(0.68f, 0.7f, 0.73f); private static readonly Color ColText = new Color(0.84f, 0.84f, 0.84f); private static readonly Color ColHead = new Color(0.88f, 0.84f, 0.72f); private static readonly Color ColGold = new Color(0.95f, 0.87f, 0.55f); private static GUIStyle _panel; private static GUIStyle _title; private static GUIStyle _cell; private static GUIStyle _head; private static GUIStyle _foot; private static GUIStyle _toastStyle; private static GUIStyle _tab; private static GUIStyle _tabActive; private static GUIStyle _wrapCell; private static GUIStyle _titleText; private static Texture2D _bg; private static Texture2D _bgTitle; private static Texture2D _bgToast; private static Texture2D _bgTab; private static Texture2D _bgTabActive; private static bool _stylesReady; private static Vector2 _scroll; private static int _tabIndex; private static Rect _mainRect = new Rect(20f, 70f, 760f, 0f); private static Rect _detailRect = new Rect(20f, 40f, 660f, 0f); private static readonly GUILayoutOption[] W60 = (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }; private static readonly GUILayoutOption[] W80 = (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }; private static readonly GUILayoutOption[] W90 = (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }; private static readonly GUILayoutOption[] W100 = (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) }; private static readonly GUILayoutOption[] W110 = (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) }; private static readonly GUILayoutOption[] W120 = (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }; private static readonly GUILayoutOption[] W130 = (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(130f) }; private static readonly GUILayoutOption[] W150 = (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) }; private static readonly GUILayoutOption[] W170 = (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(170f) }; private static readonly GUILayoutOption[] W200 = (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) }; private static readonly GUILayoutOption[] W230 = (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(230f) }; private static readonly GUILayoutOption[] H280 = (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(280f) }; private static readonly GUILayoutOption[] NoOpts = (GUILayoutOption[])(object)new GUILayoutOption[0]; private static readonly List<Toast> _toasts = new List<Toast>(); private const float RebuildInterval = 0.5f; private static float _nextRebuild; private static bool _forceRebuild; private static string _mTitle = ""; private static readonly List<Cell[]> _mRows = new List<Cell[]>(); private static readonly List<Cell[]> _mSettings = new List<Cell[]>(); private static readonly List<Cell> _mNotes = new List<Cell>(); private static string[] _mHeaders = Array.Empty<string>(); private static GUILayoutOption[][] _mRowWidths = Array.Empty<GUILayoutOption[]>(); private static string _dSummary = ""; private static string _dBiome; private static string _dNoData; private static Cell[] _dSyncLine = Array.Empty<Cell>(); private static string[] _dTabs = Array.Empty<string>(); private static readonly List<Cell[]> _dRows = new List<Cell[]>(); private static readonly GUILayoutOption[][] _dRowWidths = new GUILayoutOption[6][] { W230, W120, W60, W60, W60, W60 }; private static string _dFirstDiv = "无"; private const int DetailRowCap = 60; private static string _dOverflow; public static bool WantsDraw { get { if (!ShowPanel && !ShowDetail) { return _toasts.Count > 0; } return true; } } public static void AddToast(string msg) { _toasts.Add(new Toast { Msg = msg, Until = Time.unscaledTime + 10f }); Plugin.Log.LogWarning((object)msg); } public static void Invalidate() { _forceRebuild = true; } private static Texture2D Tex(Color c) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown Texture2D val = new Texture2D(1, 1); val.SetPixel(0, 0, c); val.Apply(); return val; } private static void EnsureStyles() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Expected O, but got Unknown //IL_00e2: Expected O, but got Unknown //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Expected O, but got Unknown //IL_0134: Expected O, but got Unknown //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Expected O, but got Unknown //IL_0165: Expected O, but got Unknown //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Expected O, but got Unknown //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Expected O, but got Unknown //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Expected O, but got Unknown //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Expected O, but got Unknown //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Expected O, but got Unknown //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Expected O, but got Unknown //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: Expected O, but got Unknown //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Expected O, but got Unknown //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Expected O, but got Unknown if (!_stylesReady) { _bg = Tex(new Color(0.08f, 0.086f, 0.098f, 0.92f)); _bgTitle = Tex(new Color(0.2f, 0.215f, 0.235f, 1f)); _bgToast = Tex(new Color(0.12f, 0.09f, 0.09f, 0.92f)); _bgTab = Tex(new Color(0.15f, 0.16f, 0.176f, 1f)); _bgTabActive = Tex(new Color(0.23f, 0.2f, 0.145f, 1f)); GUIStyle val = new GUIStyle(); val.normal.background = _bg; val.padding = new RectOffset(10, 10, 6, 8); _panel = val; GUIStyle val2 = new GUIStyle(); val2.normal.background = _bgTitle; val2.normal.textColor = new Color(0.91f, 0.91f, 0.91f); val2.fontSize = 14; val2.padding = new RectOffset(10, 10, 6, 6); _title = val2; GUIStyle val3 = new GUIStyle(); val3.normal.textColor = ColText; val3.fontSize = 13; val3.padding = new RectOffset(4, 4, 3, 3); _cell = val3; GUIStyle val4 = new GUIStyle(_cell); val4.normal.textColor = ColGray; val4.fontSize = 12; _head = val4; GUIStyle val5 = new GUIStyle(_cell); val5.normal.textColor = ColGray; val5.fontSize = 11; val5.wordWrap = true; val5.richText = true; _foot = val5; GUIStyle val6 = new GUIStyle(); val6.normal.background = _bgToast; val6.normal.textColor = new Color(0.89f, 0.78f, 0.78f); val6.fontSize = 13; val6.padding = new RectOffset(10, 10, 6, 6); val6.wordWrap = true; _toastStyle = val6; GUIStyle val7 = new GUIStyle(); val7.normal.background = _bgTab; val7.normal.textColor = ColGray; val7.fontSize = 12; val7.padding = new RectOffset(12, 12, 3, 3); val7.alignment = (TextAnchor)4; _tab = val7; GUIStyle val8 = new GUIStyle(_tab); val8.normal.background = _bgTabActive; val8.normal.textColor = new Color(0.82f, 0.56f, 0.56f); _tabActive = val8; _wrapCell = new GUIStyle(_cell) { wordWrap = true }; GUIStyle val9 = new GUIStyle(); val9.normal.textColor = new Color(0.91f, 0.91f, 0.91f); val9.fontSize = 14; _titleText = val9; _stylesReady = true; } } private static void Label(string text, Color c, GUIStyle style, GUILayoutOption[] opts) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) Color textColor = style.normal.textColor; style.normal.textColor = c; GUILayout.Label(text, style, opts); style.normal.textColor = textColor; } public static void Draw() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Invalid comparison between Unknown and I4 //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Expected O, but got Unknown //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown if (!WantsDraw) { return; } EnsureStyles(); DrawToasts(); if ((!ShowPanel && !ShowDetail) || InPauseMenu()) { return; } if ((int)Event.current.type == 8 && (_forceRebuild || Time.unscaledTime >= _nextRebuild)) { _forceRebuild = false; _nextRebuild = Time.unscaledTime + 0.5f; if (ShowDetail) { RebuildDetail(); } else { RebuildMain(); } } if (ShowDetail) { Rect detailRect = _detailRect; object obj = <>O.<0>__DrawDetailWindow; if (obj == null) { WindowFunction val = DrawDetailWindow; <>O.<0>__DrawDetailWindow = val; obj = (object)val; } _detailRect = GUILayout.Window(93442, detailRect, (WindowFunction)obj, GUIContent.none, _panel, Array.Empty<GUILayoutOption>()); } else { Rect mainRect = _mainRect; object obj2 = <>O.<1>__DrawMainWindow; if (obj2 == null) { WindowFunction val2 = DrawMainWindow; <>O.<1>__DrawMainWindow = val2; obj2 = (object)val2; } _mainRect = GUILayout.Window(93441, mainRect, (WindowFunction)obj2, GUIContent.none, _panel, Array.Empty<GUILayoutOption>()); } } private static bool InPauseMenu() { try { return GUIManager.InPauseMenu; } catch { return false; } } private static void DrawToasts() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) _toasts.RemoveAll((Toast t) => Time.unscaledTime > t.Until); float num = 10f; foreach (Toast toast in _toasts) { GUI.Label(new Rect(10f, num, 470f, 44f), toast.Msg, _toastStyle); num += 50f; } } private static Version SafeVer(string s) { try { return string.IsNullOrEmpty(s) ? null : new Version(s); } catch { return null; } } private static Color VerColor(string ver, Version latest) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) Version version = SafeVer(ver); if (version == null) { return ColGray; } if (latest != null && version < latest) { return ColRed; } return ColGreen; } private static Cell VerCell(string ver, string prefix, Version latest) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) if (ver != null) { return new Cell(prefix + "_" + ver, VerColor(ver, latest)); } return new Cell(Loc.T("Unknown", "未知"), ColGray); } private static Cell BakeCell(string flag, bool forced) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) string text = ((flag == "1") ? Loc.T("On", "启用") : ((flag == "0") ? Loc.T("Off", "关闭") : Loc.T("Unknown", "未知"))); if (forced) { text += Loc.T(" (forced)", " (已强制跟随)"); } return new Cell(text, (flag == "?") ? ColGray : ColGold); } private static Cell UnknownCell() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) return new Cell(Loc.T("Unknown", "未知"), ColGray); } private static void RebuildMain() { //IL_033b: Unknown result type (might be due to invalid IL or missing references) //IL_038d: Unknown result type (might be due to invalid IL or missing references) //IL_0386: Unknown result type (might be due to invalid IL or missing references) //IL_03fa: Unknown result type (might be due to invalid IL or missing references) //IL_0518: Unknown result type (might be due to invalid IL or missing references) //IL_051d: Unknown result type (might be due to invalid IL or missing references) //IL_052a: Unknown result type (might be due to invalid IL or missing references) //IL_050a: Unknown result type (might be due to invalid IL or missing references) //IL_0511: Unknown result type (might be due to invalid IL or missing references) //IL_05c0: Unknown result type (might be due to invalid IL or missing references) //IL_05b9: Unknown result type (might be due to invalid IL or missing references) _mRows.Clear(); _mSettings.Clear(); _mNotes.Clear(); LocalMods.EnsureDetected(); Player[] array = (PhotonNetwork.InRoom ? PhotonNetwork.PlayerList : Array.Empty<Player>()); Dictionary<int, Plugin.PlayerInfo> dictionary = new Dictionary<int, Plugin.PlayerInfo>(array.Length); Player[] array2 = array; foreach (Player val in array2) { dictionary[val.ActorNumber] = Plugin.ParsePlayer(val); } Version version = null; Version version2 = null; Version version3 = SafeVer("1.0.20"); foreach (Plugin.PlayerInfo value2 in dictionary.Values) { Version version4 = SafeVer(value2.TrVer); if (version4 != null && (version == null || version4 > version)) { version = version4; } Version version5 = SafeVer(value2.WindVer); if (version5 != null && (version2 == null || version5 > version2)) { version2 = version5; } Version version6 = SafeVer(value2.RteVer); if (version6 != null && (version3 == null || version6 > version3)) { version3 = version6; } } if (!PhotonNetwork.InRoom) { Version version7 = SafeVer(Plugin.TrVersion); if (version7 != null) { version = version7; } Version version8 = SafeVer(Plugin.WindVersion); if (version8 != null) { version2 = version8; } } Player val2 = (PhotonNetwork.InRoom ? PhotonNetwork.MasterClient : null); if (val2 != null) { dictionary.TryGetValue(val2.ActorNumber, out var _); } bool flag = Plugin.TfaVersion != null || dictionary.Values.Any((Plugin.PlayerInfo playerInfo2) => playerInfo2.TfaVer != null); bool flag2 = Plugin.WindVersion != null || dictionary.Values.Any((Plugin.PlayerInfo playerInfo2) => playerInfo2.WindVer != null); List<string> list = new List<string> { Loc.T("Player (·mod ver)", "玩家 (·本模组版本)") }; List<GUILayoutOption[]> list2 = new List<GUILayoutOption[]> { W200 }; list.Add(Loc.T("Randomiser", "随机地形")); list2.Add(W90); if (flag) { list.Add("TFA"); list2.Add(W60); } if (flag2) { list.Add(Loc.T("Wind", "挡风")); list2.Add(W80); } list.Add(Loc.T("Baking", "光照烘焙")); list2.Add(W110); list.Add(Loc.T("Sync", "同步状态")); list2.Add(W120); _mHeaders = list.ToArray(); _mRowWidths = list2.ToArray(); _mTitle = Loc.T("RandomTerrainEnhance v1.0.20 — Room Sync Status", "随机地形增强 v1.0.20 — 房间同步状态"); List<Cell> list3 = new List<Cell>(_mHeaders.Length); if (!PhotonNetwork.InRoom) { bool? localBake = Plugin.GetLocalBake(); list3.Add(new Cell(Loc.T("Local (offline) ·RTE1.0.20", "本机 (未联机) ·RTE1.0.20"), ColText)); list3.Add(VerCell(Plugin.TrVersion, Loc.T("TR", "随机"), version)); if (flag) { list3.Add(new Cell(Plugin.TfaVersion ?? "—", (Plugin.TfaVersion == null) ? ColGray : ColGreen)); } if (flag2) { list3.Add(VerCell(Plugin.WindVersion, Loc.T("Wind", "挡风"), version2)); } list3.Add(BakeCell((!localBake.HasValue) ? "?" : (localBake.Value ? "1" : "0"), forced: false)); list3.Add(new Cell("—", ColGray)); _mRows.Add(list3.ToArray()); } else { foreach (Player item in array.OrderByDescending((Player p) => p.IsMasterClient)) { Plugin.PlayerInfo playerInfo = dictionary[item.ActorNumber]; string text = (playerInfo.HasPatch ? (" ·RTE" + (playerInfo.RteVer ?? "?")) : Loc.T(" ·no-mod", " ·无本模组")); string t = Names.Truncate(item.NickName, 10) + (item.IsMasterClient ? Loc.T(" (Host)", " (主机)") : "") + text; Version version9 = SafeVer(playerInfo.RteVer); Color c = ((!playerInfo.HasPatch) ? ColGray : ((version9 != null && version3 != null && version9 < version3) ? ColRed : ColText)); list3.Clear(); list3.Add(new Cell(t, c)); if (!playerInfo.HasPatch) { for (int num = 1; num < _mHeaders.Length; num++) { list3.Add(UnknownCell()); } _mRows.Add(list3.ToArray()); continue; } list3.Add(VerCell(playerInfo.TrVer, Loc.T("TR", "随机"), version)); if (flag) { list3.Add(new Cell(playerInfo.TfaVer ?? "—", (playerInfo.TfaVer == null) ? ColGray : ColGreen)); } if (flag2) { list3.Add(VerCell(playerInfo.WindVer, Loc.T("Wind", "挡风"), version2)); } list3.Add(BakeCell(playerInfo.Bake, playerInfo.Forced && !item.IsMasterClient)); list3.Add(SyncCell(item)); _mRows.Add(list3.ToArray()); } } BuildSettings(flag, flag2); BuildNotes(dictionary, array, version, version2, version3); } private static Cell SyncCell(Player p) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) if (p.IsMasterClient) { return new Cell(Loc.T("Baseline", "基准"), ColGreen); } if (!SyncCheck.Results.TryGetValue(p.ActorNumber, out var value)) { return new Cell("", ColText); } string curB = SyncCheck.CurrentBiomeZh; float num2; string arg; if (!string.IsNullOrEmpty(curB)) { int num = value.Mismatches.Count((SyncCheck.Mismatch m) => m.Biome == curB); num2 = ((SyncCheck.BiomeTotals.TryGetValue(curB, out var value2) && value2 > 0) ? ((float)num / (float)value2 * 100f) : ((num > 0) ? 100f : 0f)); arg = Loc.Biome(curB); } else { num2 = value.Rate; arg = Loc.T("Whole Map", "全图"); } bool flag = num2 < Plugin.AlertThreshold.Value; return new Cell($"[{arg}][{num2:F1}%]", flag ? ColGreen : ColRed); } private static Cell OnOff(bool? v) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) if (!v.HasValue) { return new Cell("?", ColGray); } return new Cell(v.Value ? Loc.T("On", "开") : Loc.T("Off", "关"), ColGold); } private static void AddSetting(string name, Cell host, Cell eff, string note, Color noteCol) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) _mSettings.Add(new Cell[4] { new Cell(name, ColText), host, eff, new Cell(note, noteCol) }); } private static void BuildSettings(bool anyTfa, bool anyWind) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_0444: Unknown result type (might be due to invalid IL or missing references) //IL_0449: Unknown result type (might be due to invalid IL or missing references) //IL_04e1: Unknown result type (might be due to invalid IL or missing references) //IL_04da: Unknown result type (might be due to invalid IL or missing references) //IL_05f8: Unknown result type (might be due to invalid IL or missing references) //IL_0625: Unknown result type (might be due to invalid IL or missing references) //IL_02fd: Unknown result type (might be due to invalid IL or missing references) //IL_0302: Unknown result type (might be due to invalid IL or missing references) //IL_056c: Unknown result type (might be due to invalid IL or missing references) //IL_036c: Unknown result type (might be due to invalid IL or missing references) //IL_05a5: Unknown result type (might be due to invalid IL or missing references) //IL_059e: Unknown result type (might be due to invalid IL or missing references) //IL_03cb: Unknown result type (might be due to invalid IL or missing references) //IL_0373: Unknown result type (might be due to invalid IL or missing references) //IL_039a: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Unknown result type (might be due to invalid IL or missing references) //IL_05d3: Unknown result type (might be due to invalid IL or missing references) bool flag = !PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient; bool flag2 = anyTfa && Arbiter.TfaLoaded && Arbiter.FaRun(); if (!flag2 && TcSession.OwnsMap()) { AddSetting(Loc.T("Terrain source", "本局地形"), new Cell(Loc.T("Custom", "定制器"), ColText), new Cell("—", ColGray), Loc.T("TerrainCustomiser custom map; this mod stands aside this round. Sync info: TerrainCustomiser panel (F11)", "地形定制器自定义图,本模组本局不介入;同步信息见地形定制器面板(F11)"), ColGray); return; } string text = ((SyncCheck.LocalSeed != 0) ? SyncCheck.LocalSeed.ToString() : "—"); ITerrainTarget genTarget = SyncCheck.GenTarget; string t = (flag2 ? "TFA" : ((genTarget == null) ? Loc.T("vanilla", "原版") : Loc.T("Random", "随机"))); string text2 = (flag2 ? Loc.T("TFA Final Ascent", "TFA 最终天阶") : ((genTarget == null) ? Loc.T("vanilla", "原版") : (Loc.Zh ? genTarget.NameZh : genTarget.NameEn))); string note = Loc.T("seed " + text + " · " + text2 + " · ", "种子 " + text + " · " + text2 + " · ") + (flag2 ? Loc.T("Final Ascent builds its own mountain; the settings below don't apply this round", "最终天阶自己拼山,下面的设置本局不生效") : Loc.T("everyone must generate the same map", "全员必须生成同一张图")); AddSetting(Loc.T("Terrain source", "本局地形"), new Cell(t, ColText), new Cell("—", ColGray), note, ColGray); ITerrainTarget[] all = Targets.All; foreach (ITerrainTarget terrainTarget in all) { if (terrainTarget.Version != null) { TargetState state = terrainTarget.State; bool flag3 = (state.HasLocked ? state.FixActive : Negotiate.Decide(terrainTarget, Cap.Rng)); bool flag4 = (state.HasLocked ? state.ViewFixActive : Negotiate.Decide(terrainTarget, Cap.ViewId)); bool? v = (flag ? new bool?(Negotiate.LocalSwitch(Cap.Rng)) : Negotiate.GetRoomBool(terrainTarget.Keys.Fix)); bool? v2 = (flag ? new bool?(Negotiate.LocalSwitch(Cap.ViewId)) : Negotiate.GetRoomBool(terrainTarget.Keys.ViewFix)); string text3 = (state.HasLocked ? Loc.T("this round", "本局") : Loc.T("next round", "下一局")); string text4 = Negotiate.ForcedOffReason(terrainTarget); string text5 = state.OffReason ?? ((text4 != null) ? Loc.T("disabled room-wide: " + text4 + " lack this mod", "已全房关闭:" + text4 + " 未装本模组") : null); Cell eff = OnOff(flag3); if (v == true && !flag3) { eff.Color = ColRed; } AddSetting(Loc.T("RNG isolation", "随机流隔离"), OnOff(v), eff, (text5 != null && v == true && !flag3) ? text5 : Loc.T("Host decides; everyone needs this mod (" + text3 + ")", "主机决定,需全员装本模组(" + text3 + ")"), (text5 != null && v == true && !flag3) ? ColRed : ColGray); Cell eff2 = OnOff(flag4); if (v2 == true && !flag4) { eff2.Color = ColRed; } AddSetting(Loc.T("ViewID alignment", "ViewID 对齐"), OnOff(v2), eff2, Loc.T("Statues, berries, chests become interactable on clients", "决定客机的雕像/果子/箱子能否交互"), ColGray); } } bool? v3 = Plugin.GetRoomBake() ?? (flag ? Plugin.GetLocalBake() : ((bool?)null)); bool? localBake = Plugin.GetLocalBake(); Cell eff3 = OnOff(localBake); if (v3.HasValue && localBake.HasValue && v3.Value != localBake.Value) { eff3.Color = ColRed; } string text6 = Loc.T("Clients follow the host", "客机跟随主机"); if (anyWind) { text6 += Loc.T((v3 == true) ? "; wind mod off" : "; wind mod on", (v3 == true) ? ",挡风模组关" : ",挡风模组开"); } if (Plugin.BakePending) { text6 += Loc.T(" — applies next round", "(下一局生效)"); } AddSetting(Loc.T("Lightmap baking", "光照烘焙"), OnOff(v3), eff3, text6, Plugin.BakePending ? ColRed : ColGray); if (WindShelter.Enable != null && WindShelter.Enable.Value && Plugin.WindVersion == null) { bool flag5 = (Plugin.GetRoomBake() ?? Plugin.GetLocalBake()) == false && (!Arbiter.TfaLoaded || !Arbiter.FaRun()); AddSetting(Loc.T("Storm shelter", "风暴遮蔽"), new Cell("—", ColGray), new Cell(flag5 ? Loc.T("raycast", "射线") : Loc.T("lightmap", "光照"), flag5 ? ColGold : ColGray), flag5 ? Loc.T("baking off → upwind raycast (built-in); per-PC, local only", "烘焙关→上风射线判定(内置);各机本地、不影响同步") : Loc.T("baking on → uses the baked lightmap", "烘焙开→用烘焙好的光照体积"), ColGray); } if (Plugin.EnableSceneGuard != null) { AddSetting(Loc.T("Client scene guard", "客机场景守卫"), new Cell("—", ColGray), OnOff(Plugin.EnableSceneGuard.Value), Loc.T("Stops slow clients reloading the island (host invisible, items gone)", "防慢客机开局重载岛(看不见主机、物品消失)"), ColGray); } } private static void BuildNotes(Dictionary<int, Plugin.PlayerInfo> infos, Player[] players, Version latestTr, Version latestWind, Version latestRte) { //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) List<string> list = new List<string>(); List<string> list2 = new List<string>(); foreach (Player val in players) { if (!infos.TryGetValue(val.ActorNumber, out var value)) { continue; } if (!value.HasPatch) { list.Add(Names.Truncate(val.NickName, 10)); continue; } Version version = SafeVer(value.RteVer); if (version != null && latestRte != null && version < latestRte) { list2.Add(Names.Truncate(val.NickName, 10) + " " + value.RteVer); } } if (list.Count > 0) { _mNotes.Add(new Cell(Loc.T("Without this mod: " + string.Join(", ", list.ToArray()) + " — room-wide fixes are off", "未装本模组:" + string.Join("、", list.ToArray()) + " —— 全房的改流修复因此关闭"), ColRed)); } if (list2.Count > 0) { _mNotes.Add(new Cell(Loc.T(string.Format("Older version: {0} (newest {1})", string.Join(", ", list2.ToArray()), latestRte), string.Format("版本落后:{0}(房内最新 {1})", string.Join("、", list2.ToArray()), latestRte)), ColRed)); } if (!string.IsNullOrEmpty(SyncCheck.BiomeSummaryShort)) { _mNotes.Add(new Cell(Loc.T("Biomes: " + SyncCheck.BiomeSummaryShort, "生态:" + SyncCheck.BiomeSummaryShort), ColGray)); } _mNotes.Add(new Cell(Loc.T("Version baseline: randomiser " + (latestTr?.ToString() ?? "?") + ((latestWind != null) ? $" / wind {latestWind}" : "") + " · Sync column = current biome only, hold F8 for detail", "版本基准:随机地形 " + (latestTr?.ToString() ?? "?") + ((latestWind != null) ? $" / 挡风 {latestWind}" : "") + " · 同步状态列只算当前生态,长按 F8 看明细"), ColGray)); } private static void DrawMainWindow(int _) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_0325: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginHorizontal(_title, Array.Empty<GUILayoutOption>()); GUILayout.Label(_mTitle, _titleText, NoOpts); GUILayout.FlexibleSpace(); Label(Loc.T("F8 close · hold F8 details", "F8 关闭 · 长按F8 详情"), ColGray, _head, NoOpts); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); for (int i = 0; i < _mHeaders.Length && i < _mRowWidths.Length; i++) { GUILayout.Label(_mHeaders[i], _head, _mRowWidths[i]); } GUILayout.EndHorizontal(); foreach (Cell[] mRow in _mRows) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); for (int j = 0; j < mRow.Length && j < _mRowWidths.Length; j++) { Label(mRow[j].Text, mRow[j].Color, _cell, _mRowWidths[j]); } GUILayout.EndHorizontal(); } GUILayout.Space(8f); Label(Loc.T("Multiplayer sync settings", "联机同步设置"), ColHead, _cell, NoOpts); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label(Loc.T("Setting", "设置项"), _head, W170); GUILayout.Label(Loc.T("Host", "主机"), _head, W60); GUILayout.Label(Loc.T("This PC", "本机生效"), _head, W80); GUILayout.Label(Loc.T("Note", "说明"), _head, NoOpts); GUILayout.EndHorizontal(); foreach (Cell[] mSetting in _mSettings) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); Label(mSetting[0].Text, mSetting[0].Color, _cell, W170); Label(mSetting[1].Text, mSetting[1].Color, _cell, W60); Label(mSetting[2].Text, mSetting[2].Color, _cell, W80); Label(mSetting[3].Text, mSetting[3].Color, _foot, NoOpts); GUILayout.EndHorizontal(); } if (_mNotes.Count > 0) { GUILayout.Space(6f); foreach (Cell mNote in _mNotes) { Label(mNote.Text, mNote.Color, _foot, NoOpts); } } GUI.DragWindow(new Rect(0f, 0f, 10000f, 30f)); } private static void RebuildDetail() { //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_02e5: Unknown result type (might be due to invalid IL or missing references) //IL_03ca: Unknown result type (might be due to invalid IL or missing references) //IL_03fe: Unknown result type (might be due to invalid IL or missing references) //IL_043a: Unknown result type (might be due to invalid IL or missing references) //IL_0457: Unknown result type (might be due to invalid IL or missing references) //IL_048b: Unknown result type (might be due to invalid IL or missing references) //IL_0484: Unknown result type (might be due to invalid IL or missing references) //IL_04d5: Unknown result type (might be due to invalid IL or missing references) //IL_04ce: Unknown result type (might be due to invalid IL or missing references) _dRows.Clear(); _dNoData = null; _dBiome = null; string arg = ((SyncCheck.LocalSeed != 0) ? SyncCheck.LocalSeed.ToString() : Loc.T("Unknown", "未知")); string arg2 = ((SyncCheck.LastCheckTime == default(DateTime)) ? "—" : SyncCheck.LastCheckTime.ToString("HH:mm:ss")); _dSummary = Loc.T($"Seed {arg} · {SyncCheck.LocalTotal} spawners · checked at {arg2}", $"本图种子 {arg} · spawner 总数 {SyncCheck.LocalTotal} · 校验时间 {arg2}"); if (!string.IsNullOrEmpty(SyncCheck.BiomeSummary)) { _dBiome = Loc.T("Biomes: " + SyncCheck.BiomeSummary, "当前生态:" + SyncCheck.BiomeSummary); } List<SyncCheck.Result> list = SyncCheck.Results.Values.OrderByDescending((SyncCheck.Result r) => r.Mismatches.Count).ToList(); float th = Plugin.AlertThreshold.Value; List<SyncCheck.Result> list2 = list.Where((SyncCheck.Result r) => r.Mismatches.Count > 0).ToList(); List<SyncCheck.Result> list3 = list2.Where((SyncCheck.Result r) => r.Rate >= th).ToList(); List<SyncCheck.Result> list4 = list.Where((SyncCheck.Result r) => r.Mismatches.Count == 0 || r.Rate < th).ToList(); if (list.Count == 0) { _dNoData = Loc.T("No sync data yet (collected ~10s after generation; the other player needs this patch installed)", "尚未收到校验数据(生成完成约 10 秒后自动统计;对方需安装本补丁)"); _dSyncLine = Array.Empty<Cell>(); _dTabs = Array.Empty<string>(); return; } List<Cell> list5 = new List<Cell> { new Cell(Loc.T($"Sync: {list4.Count}/{list.Count}", $"同步情况:{list4.Count}/{list.Count}"), (list4.Count == list.Count) ? ColGreen : ColText) }; if (list3.Count > 0) { list5.Add(new Cell(Loc.T(", desynced: ", ",不同步玩家:"), ColText)); list5.Add(new Cell(string.Join(" | ", list3.Select((SyncCheck.Result r) => Loc.T($"{Names.Truncate(r.Nick, 12)} {r.MatchCount}/{r.Total} match, {r.Mismatches.Count} desynced {r.Rate:F1}%", $"{Names.Truncate(r.Nick, 12)} {r.MatchCount}/{r.Total} 一致,{r.Mismatches.Count} 项不同步 {r.Rate:F1}%"))), ColRed)); } if (list4.Count > 0) { list5.Add(new Cell(Loc.T(" in sync: ", " 同步:"), ColGray)); list5.Add(new Cell(string.Join(" | ", list4.Select((SyncCheck.Result r) => Names.Truncate(r.Nick, 12) + ((r.Mismatches.Count > 0) ? $"({r.Rate:F1}%)" : ""))), ColGray)); } _dSyncLine = list5.ToArray(); if (list2.Count == 0) { _dTabs = Array.Empty<string>(); return; } if (_tabIndex >= list2.Count) { _tabIndex = 0; } _dTabs = list2.Select(delegate(SyncCheck.Result r) { List<string> list6 = (from m in r.Mismatches select Loc.Biome(SyncCheck.BiomeOfSegmentName(m.Biome ?? "")) into b where !string.IsNullOrEmpty(b) && b != "?" select b).Distinct().Take(3).ToList(); string text = ((list6.Count == 0) ? "" : (" [" + string.Join("·", list6) + "]")); return Loc.T($"{Names.Truncate(r.Nick, 10)}{text}[{r.Mismatches.Count}][{r.Rate:F1}%]", $"{Names.Truncate(r.Nick, 10)}{text}[{r.Mismatches.Count}项][{r.Rate:F1}%]"); }).ToArray(); SyncCheck.Result result = list2[_tabIndex]; int num = Math.Min(result.Mismatches.Count, 60); for (int num2 = 0; num2 < num; num2++) { SyncCheck.Mismatch mismatch = result.Mismatches[num2]; _dRows.Add(new Cell[6] { new Cell(Names.Truncate($"{mismatch.Name} (#{(uint)mismatch.Id % 10000u})", 30), ColText), new Cell(Names.Truncate(Loc.Zh ? Names.Translate(mismatch.Name) : mismatch.Name, 10), ColText), new Cell(Names.Truncate(Loc.Biome(SyncCheck.BiomeOfSegmentName(mismatch.Biome ?? "")), Loc.Zh ? 6 : 10), ColText), new Cell(mismatch.HostCount.ToString(), ColText), new Cell(mismatch.TheirCount.ToString(), (mismatch.TheirCount == mismatch.HostCount) ? ColText : ColRed), new Cell(mismatch.PosDiff ? Loc.T("Diff", "不一致") : Loc.T("Same", "一致"), mismatch.PosDiff ? ColRed : ColGreen) }); } _dOverflow = ((result.Mismatches.Count > 60) ? Loc.T($"… {result.Mismatches.Count - 60} more rows omitted (full list in sync_report_*.log)", $"… 另有 {result.Mismatches.Count - 60} 条已省略(完整清单见 sync_report_*.log)") : null); _dFirstDiv = result.FirstDivergence ?? Loc.T("None", "无"); } private static void DrawDetailWindow(int _) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_037b: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Unknown result type (might be due to invalid IL or missing references) //IL_0330: Unknown result type (might be due to invalid IL or missing references) //IL_0353: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginHorizontal(_title, Array.Empty<GUILayoutOption>()); GUILayout.Label(Loc.T("Sync Details (hold F8 to open)", "同步数据详情(长按 F8 展开)"), _titleText, NoOpts); GUILayout.FlexibleSpace(); Label(Loc.T("short press F8 to return", "短按F8返回"), ColGray, _head, NoOpts); GUILayout.EndHorizontal(); Label(Loc.T("Check Summary", "校验概况"), ColHead, _cell, NoOpts); Label(_dSummary, ColText, _cell, NoOpts); if (_dBiome != null) { Label(_dBiome, ColText, _wrapCell, NoOpts); } if (_dNoData != null) { Label(_dNoData, ColGray, _cell, NoOpts); } else if (_dSyncLine.Length != 0) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); Cell[] dSyncLine = _dSyncLine; for (int i = 0; i < dSyncLine.Length; i++) { Cell cell = dSyncLine[i]; Label(cell.Text, cell.Color, _cell, NoOpts); } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); } if (_dTabs.Length != 0) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); for (int j = 0; j < _dTabs.Length; j++) { if (GUILayout.Button(_dTabs[j], (j == _tabIndex) ? _tabActive : _tab, NoOpts) && _tabIndex != j) { _tabIndex = j; Invalidate(); } } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label("Spawner (ID)", _head, W230); GUILayout.Label(Loc.T("Name", "译名"), _head, W120); GUILayout.Label(Loc.T("Biome", "生态"), _head, W60); GUILayout.Label(Loc.T("Host", "主机"), _head, W60); GUILayout.Label(Loc.T("Theirs", "对方"), _head, W60); GUILayout.Label(Loc.T("Pos", "位置"), _head, W60); GUILayout.EndHorizontal(); _scroll = GUILayout.BeginScrollView(_scroll, H280); foreach (Cell[] dRow in _dRows) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); for (int k = 0; k < dRow.Length; k++) { Label(dRow[k].Text, dRow[k].Color, _cell, _dRowWidths[k]); } GUILayout.EndHorizontal(); } GUILayout.EndScrollView(); if (_dOverflow != null) { Label(_dOverflow, ColGray, _foot, NoOpts); } Label(Loc.T("First Divergence", "首个分叉点"), ColHead, _cell, NoOpts); Label(_dFirstDiv, ColText, _cell, NoOpts); Label(Loc.T("Details broadcast to everyone's log: BepInEx\\config\\随机地形增强\\sync_report_*.log", "明细已广播至全员日志:BepInEx\\config\\随机地形增强\\sync_report_*.log"), ColGray, _foot, NoOpts); } GUI.DragWindow(new Rect(0f, 0f, 10000f, 30f)); } } internal static class LanguageConfig { private static string _existing; internal static void Capture(ConfigFile config) { _existing = (File.Exists(config.ConfigFilePath) ? File.ReadAllText(config.ConfigFilePath) : ""); } internal static ConfigEntry<T> Bind<T>(ConfigFile config, string enSection, string zhSection, string enKey, string zhKey, T value, string description) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown return Bind(config, enSection, zhSection, enKey, zhKey, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>())); } internal static ConfigEntry<T> Bind<T>(ConfigFile config, string enSection, string zhSection, string enKey, string zhKey, T value, ConfigDescription description) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 SystemLanguage systemLanguage = Application.systemLanguage; int num; string text; if ((int)systemLanguage != 6 && (int)systemLanguage != 40) { num = (((int)systemLanguage == 41) ? 1 : 0); if (num == 0) { text = enSection; goto IL_001e; } } else { num = 1; } text = zhSection; goto IL_001e; IL_001e: string text2 = text; string text3 = ((num != 0) ? zhKey : enKey); string[][] array = new string[3][] { new string[2] { text2, text3 }, new string[2] { enSection, enKey }, new string[2] { zhSection, zhKey } }; foreach (string[] array2 in array) { if (Regex.IsMatch(Regex.Match(_existing, "(?ms)^\\[" + Regex.Escape(array2[0]) + "\\]\\s*\\r?\\n(.*?)(?=^\\[|\\z)").Groups[1].Value, "(?m)^\\s*" + Regex.Escape(array2[1]) + "\\s*=")) { return config.Bind<T>(array2[0], array2[1], value, description); } } return config.Bind<T>(enSection, enKey, value, description); } } public static class Loc { private static string _setting = "Auto"; private static readonly Dictionary<string, string> BiomeEn = new Dictionary<string, string> { { "海滩", "Shore" }, { "雨林", "Tropics" }, { "森蕈", "Roots" }, { "雪山", "Alpine" }, { "方山", "Mesa" }, { "火山", "Caldera" }, { "沼泽", "Swamp" }, { "原版", "Vanilla" }, { "熔炉", "The Kiln" }, { "顶峰", "The Peak" } }; public static bool Zh => Resolve(_setting, LocalizedText.CURRENT_LANGUAGE); public static event Action Changed; public static void Init(string setting) { _setting = setting ?? "Auto"; } public static void SetLanguage(string setting) { Init(setting); Loc.Changed?.Invoke(); } public static void OnGameLanguageChanged() { Loc.Changed?.Invoke(); } public static bool Resolve(string setting, Language language) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Invalid comparison between Unknown and I4 //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Invalid comparison between Unknown and I4 if (setting == "中文") { return true; } if (setting == "English") { return false; } if ((int)language != 9) { return (int)language == 10; } return true; } public static string T(string en, string zh) { if (!Zh) { return en; } return zh; } public static string Biome(string zhKey) { if (Zh || string.IsNullOrEmpty(zhKey)) { return zhKey; } if (!BiomeEn.TryGetValue(zhKey, out var value)) { return zhKey; } return value; } } public static class LocalMods { private static ConfigEntryBase _tfaLighting; private static bool _detected; public static void EnsureDetected() { if (_detected) { return; } _detected = true; try { Type type = AccessTools.TypeByName("TrueFinalAscent.Plugin"); if (type != null) { object? obj = AccessTools.Field(type, "Lighting")?.GetValue(null); _tfaLighting = (ConfigEntryBase)((obj is ConfigEntryBase) ? obj : null); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[地形增强] 探测 TFA 配置失败: " + ex.Message)); } } public static string TfaLightingToken() { EnsureDetected(); ConfigEntryBase tfaLighting = _tfaLighting; return (((tfaLighting != null) ? tfaLighting.BoxedValue : null) as string) ?? "-"; } } public static class TcSession { private const string MAP_DATA_KEY = "TC_mapData"; private static readonly HashSet<string> OwnStates = new HashSet<string> { "WaitingForMapData", "WaitingToStartCustomMap", "LoadingCustomMap", "CustomMapReady", "InCustomMap", "LoadingEditor", "InEditor" }; private static bool _resolved; private static PropertyInfo _stateProp; public static bool OwnsMap() { try { if (PhotonNetwork.InRoom) { Hashtable customProperties = ((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties; if (customProperties != null && ((Dictionary<object, object>)(object)customProperties).TryGetValue((object)"TC_mapData", out object value) && value is byte[] array && array.Length != 0) { return true; } } if (!_resolved) { _resolved = true; Type type = AccessTools.TypeByName("TerrainCustomiser.Session.SessionState"); if (type != null) { _stateProp = AccessTools.Property(type, "Current"); } } object obj = _stateProp?.GetValue(null); return obj != null && OwnStates.Contains(obj.ToString()); } catch { return false; } } } public static class Names { private static readonly Dictionary<string, string> Map = new Dictionary<string, string> { { "Bounce Shrooms", "大型踏板菇" }, { "Shroom Spawners", "蘑菇刷新点" }, { "Glow Mushrooms", "发光蘑菇" }, { "Exploding Shrooms", "爆炸蘑菇" }, { "ExploShrooms", "爆炸蘑菇" }, { "PoisonShrooms", "毒蘑菇" }, { "Evil Shroom", "邪恶蘑菇" }, { "Scorpion", "蝎子" }, { "Scorpions", "蝎子" }, { "Spiders", "蜘蛛" }, { "Zombie Spawner", "僵尸刷新点" }, { "Vines", "藤蔓" }, { "Ivy", "常春藤" }, { "Luggage", "行李箱" }, { "LuggageSpawner", "行李箱" }, { "Root Spawner", "根须" }, { "Geysers", "间歇泉" }, { "Weed", "杂草" }, { "BeachGrass", "滩草" }, { "Driftwood", "浮木" }, { "Behive", "蜂巢" }, { "ShittyPiton", "岩钉" }, { "Monsteras", "龟背竹" }, { "FlashPlant", "闪光植物" }, { "Shrub", "灌木" }, { "Bushes", "灌木丛" }, { "Pine", "松树" }, { "Trees", "树" }, { "DeadTree", "枯树" }, { "Ice_DeadTree", "冰封枯树" }, { "Palms", "棕榈" }, { "Cacti", "仙人掌" }, { "Dynamite", "炸药" }, { "Ferns", "蕨类" } }; private static readonly Dictionary<string, string> BiomeMap = new Dictionary<string, string> { { "Shore", "海滩" }, { "Tropics", "雨林" }, { "Roots", "森蕈" }, { "Alpine", "雪山" }, { "Mesa", "方山" }, { "Volcano", "火山" }, { "Swamp", "沼泽" }, { "Vanilla", "原版" } }; private static readonly Dictionary<string, string> VariantMap = new Dictionary<string, string> { { "Default", "默认变体(Default)" }, { "NoVariant", "无变体(No Variant)" }, { "SnakeBeach", "蛇骨海滩(Snake Beach)" }, { "RedBeach", "红沙海岸(Red Beach)" }, { "BlueBeach", "深蓝海岸(Blue Beach)" }, { "JellyHell", "水母地狱(Jelly Hell)" }, { "BlackSand", "黑沙洲(Black Sand)" }, { "Lava", "熔岩区(Lava)" }, { "Pillars", "石柱群(Pillars)" }, { "Thorny", "荆棘(Thorny)" }, { "Bombs", "雷区(Bombs)" }, { "Ivy", "藤蔓谷(Ivy)" }, { "SkyJungle", "天空丛林(Sky Jungle)" }, { "Cave Mania", "狂热洞穴(Cave Mania)" }, { "Deep Water", "深水区(Deep Water)" }, { "Bomb Beetle", "伐木场(Bomb Beetle)" }, { "Deep Woods", "深林(Deep Woods)" }, { "Clearcut", "伐木林地(Clearcut)" }, { "Spiky", "尖刺重重(Spiky)" }, { "GeyserHell", "喷泉地狱(Geyser Hell)" }, { "ScorpionsHell", "毒蝎地狱(Scorpions Hell)" }, { "CacusHell", "巨仙人掌地狱(Cacus Hell)" }, { "CactusForest", "仙人掌森林(Cactus Forest)" }, { "DynamiteHell", "炸药地狱(Dynamite Hell)" }, { "TornadoHell", "龙卷风地狱(Tornado Hell)" }, { "TumblerHell", "风滚草地狱(Tumbler Hell)" }, { "Tomb", "古墓(Tomb)" } }; private static bool _templateLoaded; private static readonly KeyValuePair<string, string>[] SegmentAlias = new KeyValuePair<string, string>[14] { new KeyValuePair<string, string>("shore", "海滩"), new KeyValuePair<string, string>("beach", "海滩"), new KeyValuePair<string, string>("tropic", "雨林"), new KeyValuePair<string, string>("jungle", "雨林"), new KeyValuePair<string, string>("roots", "森蕈"), new KeyValuePair<string, string>("alpine", "雪山"), new KeyValuePair<string, string>("snow", "雪山"), new KeyValuePair<string, string>("mesa", "方山"), new KeyValuePair<string, string>("desert", "方山"), new KeyValuePair<string, string>("caldera", "火山"), new KeyValuePair<string, string>("volcano", "火山"), new KeyValuePair<string, string>("swamp", "沼泽"), new KeyValuePair<string, string>("kiln", "熔炉"), new KeyValuePair<string, string>("peak", "顶峰") }; public static string Translate(string raw) { if (string.IsNullOrEmpty(raw)) { return raw; } if (Map.TryGetValue(raw, out var value)) { return value; } foreach (KeyValuePair<string, string> item in Map) { if (raw.StartsWith(item.Key)) { return item.Value; } } return raw; } public static void LoadZhTemplate() { if (_templateLoaded) { return; } _templateLoaded = true; try { string[] files = Directory.GetFiles(Paths.PluginPath, "TerrainRandomiser_ZH*.txt", SearchOption.AllDirectories); if (files.Length == 0) { return; } string text = null; string[] array = File.ReadAllLines(files[0]); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.StartsWith("==")) { text = text2; continue; } int num = text2.IndexOf('='); if (num <= 0 || text == null) { continue; } string text3 = text2.Substring(0, num).Trim(); string text4 = text2.Substring(num + 1).Trim(); if (text3.Length != 0 && text4.Length != 0) { if (text.Contains("生态") || text.Contains("Biomes")) { BiomeMap[text3] = text4; } else if (text.Contains("变体") || text.Contains("Variants")) { VariantMap[text3] = text4; } } } Plugin.Log.LogInfo((object)("[地形增强] 已加载汉化模板: " + files[0])); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[地形增强] 汉化模板加载失败: " + ex.Message)); } } private static string StripParen(string s) { return Regex.Replace(s, "\\s*\\([^)]*\\)\\s*$", ""); } public static string Biome(string raw) { if (string.IsNullOrEmpty(raw)) { return raw; } if (!BiomeMap.TryGetValue(raw, out var value)) { return raw; } if (!value.Contains("(")) { return value + "(" + raw + ")"; } return value; } public static string Variant(string raw) { if (string.IsNullOrEmpty(raw)) { return raw; } if (!VariantMap.TryGetValue(raw, out var value)) { return raw; } if (!value.Contains("(")) { return value + "(" + raw + ")"; } return value; } public static string BiomeShort(string raw) { if (string.IsNullOrEmpty(raw)) { return raw; } if (!BiomeMap.TryGetValue(raw, out var value)) { return raw; } return StripParen(value); } public static string VariantShort(string raw) { if (string.IsNullOrEmpty(raw)) { return raw; } if (!VariantMap.TryGetValue(raw, out var value)) { return raw; } return StripParen(value); } public static string SegmentZh(string raw) { if (string.IsNullOrEmpty(raw)) { return ""; } string text = raw.ToLowerInvariant(); KeyValuePair<string, string>[] segmentAlias = SegmentAlias; for (int i = 0; i < segmentAlias.Length; i++) { KeyValuePair<string, string> keyValuePair = segmentAlias[i]; if (text.Contains(keyValuePair.Key)) { return keyValuePair.Value; } } return raw; } public static string Truncate(string s, int max) { if (string.IsNullOrEmpty(s) || s.Length <= max) { return s; } return s.Substring(0, max - 1) + "…"; } } public enum Tri { Unknown, No, Yes } public static class Negotiate { private static readonly Dictionary<string, string> _forcedOff = new Dictionary<string, string>(); private static readonly Dictionary<string, string> _toasted = new Dictionary<string, string>(); public static string ForcedOffReason(ITerrainTarget t) { if (!_forcedOff.TryGetValue(t.Id, out var value)) { return null; } return value; } public static Tri HostPatch() { if (!PhotonNetwork.InRoom) { return Tri.Unknown; } Player masterClient = PhotonNetwork.MasterClient; if (masterClient == null) { return Tri.Unknown; } if (masterClient.IsLocal) { return Tri.Yes; } if (Plugin.ParsePlayer(masterClient).HasPatch) { return Tri.Yes; } if (!RoomWatch.WithinGrace(masterClient)) { return Tri.No; } return Tri.Unknown; } public static Tri HostSupports(ITerrainTarget t) { Tri tri = HostPatch(); if (tri != Tri.Yes) { return tri; } Player masterClient = PhotonNetwork.MasterClient; if (masterClient == null) { return Tri.Unknown; } if (masterClient.IsLocal) { return Tri.Yes; } if (!Plugin.ParsePlayer(masterClient).Supports(t.Id)) { return Tri.No; } return Tri.Yes; } public static bool? GetRoomBool(string key) { if (!PhotonNetwork.InRoom) { return null; } Hashtable customProperties = ((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties; if (customProperties != null && ((Dictionary<object, object>)(object)customProperties).TryGetValue((object)key, out object value) && value is bool) { return (bool)value; } return null; } public static Plugin.GenLock? GetGenLock(ITerrainTarget t) { if (!PhotonNetwork.InRoom) { return null; } Hashtable customProperties = ((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties; if (customProperties == null || !((Dictionary<object, object>)(object)customProperties).TryGetValue((object)t.Keys.GenLock, out object value) || !(value is string text)) { return null; } string[] array = text.Split(new char[1] { '|' }); if (array.Length < 4 || !int.TryParse(array[0], out var result)) { return null; } return new Plugin.GenLock { Seed = result, Bake = ((array[1] == "?") ? ((bool?)null) : new bool?(array[1] == "1")), Fix = (array[2] == "1"), Vf = (array[3] == "1") }; } public static bool LocalSwitch(Cap cap) { return cap switch { Cap.Rng => Plugin.EnableGenFixes.Value, Cap.ViewId => Plugin.EnableViewFix.Value, Cap.Sync => true, _ => false, }; } public static bool Decide(ITerrainTarget t, Cap cap) { if (t == null || t.Version == null) { return false; } if ((t.Caps & cap) == 0) { return false; } if (!Arbiter.Allows(t, cap)) { return false; } bool flag = LocalSwitch(cap); if (!PhotonNetwork.InRoom) { return flag; } if (PhotonNetwork.IsMasterClient) { if ((cap == Cap.Rng || cap == Cap.ViewId) && ForcedOffReason(t) != null) { return false; } return flag; } Tri tri = HostPatch(); if (tri == Tri.No) { return false; } if (HostSupports(t) == Tri.No) { return false; } Plugin.GenLock? genLock = GetGenLock(t); if (genLock.HasValue && genLock.Value.Seed == t.GetSeed()) { if (cap != Cap.Rng) { return genLock.Value.Vf; } return genLock.Value.Fix; } bool? roomBool = GetRoomBool((cap == Cap.Rng) ? t.Keys.Fix : t.Keys.ViewFix); if (roomBool.HasValue) { return roomBool.Value; } return tri == Tri.Yes && flag; } public static List<string> ScanMissing(ITerrainTarget t) { List<string> list = new List<string>(); if (!PhotonNetwork.InRoom) { return list; } Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val in playerList) { if (val == null || val.IsLocal) { continue; } Plugin.PlayerInfo playerInfo = Plugin.ParsePlayer(val); string text = Names.Truncate(val.NickName, 12); if (!playerInfo.HasPatch) { if (!RoomWatch.WithinGrace(val)) { list.Add(text); } } else if (!playerInfo.Supports(t.Id)) { list.Add(text + "(旧版)"); } } return list; } public static void HostTick() { if (!PhotonNetwork.InRoom || !PhotonNetwork.IsMasterClient) { return; } ITerrainTarget[] all = Targets.All; foreach (ITerrainTarget terrainTarget in all) { if (terrainTarget.Version == null) { _forcedOff.Remove(terrainTarget.Id); continue; } if (!LocalSwitch(Cap.Rng) && !LocalSwitch(Cap.ViewId)) { _forcedOff.Remove(terrainTarget.Id); _toasted.Remove(terrainTarget.Id); continue; } List<string> list = ScanMissing(terrainTarget); if (list.Count == 0) { if (_forcedOff.Remove(terrainTarget.Id)) { _toasted.Remove(terrainTarget.Id); Gui.Invalidate(); } continue; } string text = string.Join("、", list.ToArray()); _forcedOff.TryGetValue(terrainTarget.Id, out var value); _forcedOff[terrainTarget.Id] = text; if (value != text) { Gui.Invalidate(); if (!_toasted.TryGetValue(terrainTarget.Id, out var value2) || value2 != text) { _toasted[terrainTarget.Id] = text; Gui.AddToast(Loc.T("[RandomTerrainEnhance] " + terrainTarget.NameEn + " enhancements disabled room-wide: " + text + " lack this mod", "[随机地形增强] 已为全房关闭" + terrainTarget.NameZh + "增强:" + text + " 未安装本模组")); } } } } public static string BuildPayload() { bool? localBake = Plugin.GetLocalBake(); string text = ((!localBake.HasValue) ? "?" : (localBake.Value ? "1" : "0")); string text2 = Arbiter.TfaVersion ?? "-"; return string.Join("|", Targets.TR.Version ?? "-", Plugin.WindVersion ?? "-", text, "1.0.20", Plugin.BakeForced ? "1" : "0", text2, "-", "-", LocalMods.TfaLightingToken().Replace('|', '/'), (Plugin.EnableSceneGuard != null && Plugin.EnableSceneGuard.Value) ? "1" : "0"); } public static void OnMasterSwitched(Player newMaster) { //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown _forcedOff.Clear(); _toasted.Clear(); ITerrainTarget[] all = Targets.All; foreach (ITerrainTarget obj in all) { obj.State.HasLocked = false; obj.State.OffReason = null; } ViewFix.Reset(); Gui.Invalidate(); if (!PhotonNetwork.InRoom) { return; } if (newMaster == null || !newMaster.IsLocal) { Plugin.Log.LogInfo((object)("[地形增强] 房主已换人(" + (((newMaster != null) ? newMaster.NickName : null) ?? "?") + "),残留房间属性将不再被采信,等待新主机重建")); return; } try { Hashtable val = new Hashtable(); all = Targets.All; for (int i = 0; i < all.Length; i++) { foreach (string item in all[i].Keys.All()) { if (((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties != null && ((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).ContainsKey((object)item)) { val[(object)item] = null; } } } if (((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties != null && ((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).ContainsKey((object)"RTE_bake")) { val[(object)"RTE_bake"] = null; } if (((Dictionary<object, object>)(object)val).Count > 0) { PhotonNetwork.CurrentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null); Plugin.Log.LogInfo((object)string.Format("{0} 已接任房主并清理 {1} 个残留房间属性,下一次 tick 按本机配置重建", "[地形增强]", ((Dictionary<object, object>)(object)val).Count)); } Arbiter.ClearStaleFaKeys("接任房主"); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[地形增强] 清理残留房间属性失败: " + ex.Message)); } } public static void OnLeftRoom() { GeneratedMapScope.Clear(); _forcedOff.Clear(); _toasted.Clear(); ITerrainTarget[] all = Targets.All; foreach (ITerrainTarget obj in all) { obj.State.HasLocked = false; obj.State.InGeneration = false; obj.State.OffReason = null; obj.State.Missing.Clear(); } ViewFix.Reset(); } } public class RoomWatch : IInRoomCallbacks, IMatchmakingCallbacks { public const float GraceSeconds = 5f; private static readonly Dictionary<int, float> _seenAt = new Dictionary<int, float>(); private static float _masterSwitchAt = -999f; public static void Note(Player p) { if (p != null && !_seenAt.ContainsKey(p.ActorNumber)) { _seenAt[p.ActorNumber] = Time.unscaledTime; } } public static bool WithinGrace(Player p) { if (p == null) { return true; } if (Time.unscaledTime - _masterSwitchAt < 5f) { return true; } if (!_seenAt.TryGetValue(p.ActorNumber, out var value)) { Note(p); return true; } return Time.unscaledTime - value < 5f; } public void OnPlayerEnteredRoom(Player newPlayer) { Note(newPlayer); Gui.Invalidate(); } public void OnPlayerLeftRoom(Player otherPlayer) { if (otherPlayer != null) { _seenAt.Remove(otherPlayer.ActorNumber); } Gui.Invalidate(); } public void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged) { Gui.Invalidate(); } public void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps) { Gui.Invalidate(); } public void OnMasterClientSwitched(Player newMasterClient) { _masterSwitchAt = Time.unscaledTime; Negotiate.OnMasterSwitched(newMasterClient); } public void OnJoinedRoom() { _seenAt.Clear(); _masterSwitchAt = Time.unscaledTime; Player[] playerList = PhotonNetwork.PlayerList; for (int i = 0; i < playerList.Length; i++) { Note(playerList[i]); } } public void OnLeftRoom() { _seenAt.Clear(); Negotiate.OnLeftRoom(); } public void OnFriendListUpdate(List<FriendInfo> friendList) { } public void OnCreatedRoom() { } public void OnC