using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using NebulaAPI;
using NebulaAPI.GameState;
using NebulaAPI.Networking;
using NebulaAPI.Packets;
using NebulaWorld;
using NebulaWorld.GameStates;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("BulletTime")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BulletTime")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("4813207f-ca55-4857-9ede-b1c9d2a90373")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.5.2.0")]
[module: UnverifiableCode]
namespace BulletTime;
internal class SkillSystem_Patch
{
public static bool Enable { get; set; }
public static void GameTick(SkillSystem skillSystem)
{
if (Enable)
{
PerformanceMonitor.BeginSample((ECpuWorkEntry)33);
PerformanceMonitor.BeginSample((ECpuWorkEntry)35);
AdvanceSkillSystem(skillSystem);
PerformanceMonitor.EndSample((ECpuWorkEntry)35);
PerformanceMonitor.BeginSample((ECpuWorkEntry)33);
}
}
private static void AdvanceSkillSystem(SkillSystem skillSystem)
{
skillSystem.PrepareTick();
skillSystem.CollectPlayerStates();
skillSystem.GameTick(GameMain.gameTick);
skillSystem.AfterTick();
}
}
internal class BuildTool_Patch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(BuildTool_Click), "CreatePrebuilds")]
[HarmonyPatch(typeof(BuildTool_Path), "CreatePrebuilds")]
[HarmonyPatch(typeof(BuildTool_Addon), "CreatePrebuilds")]
[HarmonyPatch(typeof(BuildTool_Inserter), "CreatePrebuilds")]
[HarmonyPatch(typeof(BuildTool_BlueprintPaste), "CreatePrebuilds")]
public static IEnumerable<CodeInstruction> RemoveGC_Transpiler(IEnumerable<CodeInstruction> instructions)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null).End();
for (int i = 0; i < 5; i++)
{
val.Advance(-1);
if (val.Opcode == OpCodes.Call && ((MethodInfo)val.Operand).Name == "Collect")
{
val.SetOpcodeAndAdvance(OpCodes.Nop);
break;
}
}
return val.InstructionEnumeration();
}
}
internal class GameLoader_Patch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(GameLoader), "FixedUpdate")]
private static IEnumerable<CodeInstruction> GameTick_Transpiler(IEnumerable<CodeInstruction> instructions)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Expected O, but got Unknown
try
{
return new CodeMatcher(instructions, (ILGenerator)null).MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.Method(typeof(StarData), "get_loaded", (Type[])null, (Type[])null), (string)null)
}).Advance(-1).SetAndAdvance(OpCodes.Nop, (object)null)
.SetAndAdvance(OpCodes.Nop, (object)null)
.Insert((CodeInstruction[])(object)new CodeInstruction[1] { Transpilers.EmitDelegate<Func<bool>>((Func<bool>)(() => GameMain.localPlanet?.loaded ?? true)) })
.InstructionEnumeration();
}
catch
{
Log.Warn("Transpiler GameLoader.FixedUpdate failed. Fast loading won't work");
return instructions;
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(GameLoader), "FixedUpdate")]
private static void FixedUpdate_Postfix(GameLoader __instance)
{
if (__instance.frame >= 5 && DSPGame.Game.isMenuDemo && !DSPGame.IsCombatCutscene)
{
Log.Debug("MenuDemo - Fast forward");
GameMain.data.SetReady();
GameMain.Begin();
__instance.SelfDestroy();
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(VFPreload), "IsMusicReached")]
private static void IsMusicReached_Postfix(ref bool __result)
{
__result |= true;
}
}
public static class NebulaCompat
{
public const string APIGUID = "dsp.nebula-multiplayer-api";
public const string GUID = "dsp.nebula-multiplayer";
public static bool NebulaIsInstalled { get; private set; }
public static bool IsMultiplayerActive { get; private set; }
public static bool IsClient { get; private set; }
public static bool IsPlayerJoining { get; set; }
public static List<(string username, int planetId)> LoadingPlayers { get; } = new List<(string, int)>();
public static bool DysonSpherePaused { get; set; }
public static void Init(Harmony harmony)
{
try
{
NebulaIsInstalled = NebulaModAPI.NebulaIsInstalled;
if (!NebulaIsInstalled)
{
return;
}
NebulaModAPI.RegisterPackets(Assembly.GetExecutingAssembly());
NebulaModAPI.OnMultiplayerGameStarted = (Action)Delegate.Combine(NebulaModAPI.OnMultiplayerGameStarted, new Action(OnMultiplayerGameStarted));
NebulaModAPI.OnMultiplayerGameEnded = (Action)Delegate.Combine(NebulaModAPI.OnMultiplayerGameEnded, new Action(OnMultiplayerGameEnded));
NebulaModAPI.OnPlanetLoadRequest = (Action<int>)Delegate.Combine(NebulaModAPI.OnPlanetLoadRequest, new Action<int>(OnFactoryLoadRequest));
NebulaModAPI.OnPlanetLoadFinished = (Action<int>)Delegate.Combine(NebulaModAPI.OnPlanetLoadFinished, new Action<int>(OnFactoryLoadFinished));
NebulaModAPI.OnPlayerLeftGame = (Action<IPlayerData>)Delegate.Combine(NebulaModAPI.OnPlayerLeftGame, (Action<IPlayerData>)delegate(IPlayerData player)
{
LoadingPlayers.RemoveAll(((string username, int planetId) x) => x.username == player.Username);
DetermineCurrentState();
});
harmony.PatchAll(typeof(NebulaPatch));
Log.Debug("Nebula Compatibility OK");
}
catch (Exception obj)
{
Log.Error("Nebula Compatibility failed!");
Log.Error(obj);
}
}
public static void Dispose()
{
if (NebulaIsInstalled)
{
NebulaModAPI.OnMultiplayerGameStarted = (Action)Delegate.Remove(NebulaModAPI.OnMultiplayerGameStarted, new Action(OnMultiplayerGameStarted));
NebulaModAPI.OnMultiplayerGameEnded = (Action)Delegate.Remove(NebulaModAPI.OnMultiplayerGameEnded, new Action(OnMultiplayerGameEnded));
NebulaModAPI.OnPlanetLoadRequest = (Action<int>)Delegate.Remove(NebulaModAPI.OnPlanetLoadRequest, new Action<int>(OnFactoryLoadRequest));
NebulaModAPI.OnPlanetLoadFinished = (Action<int>)Delegate.Remove(NebulaModAPI.OnPlanetLoadFinished, new Action<int>(OnFactoryLoadFinished));
}
}
public static void OnMultiplayerGameStarted()
{
IsMultiplayerActive = NebulaModAPI.IsMultiplayerActive;
IsClient = IsMultiplayerActive && NebulaModAPI.MultiplayerSession.LocalPlayer.IsClient;
IsPlayerJoining = false;
LoadingPlayers.Clear();
DysonSpherePaused = false;
GameStateManager.EnableMechaFunc = false;
NebulaPatch.SetProgessMode(enable: false);
}
public static void OnMultiplayerGameEnded()
{
IsMultiplayerActive = false;
IsClient = false;
IsPlayerJoining = false;
LoadingPlayers.Clear();
DysonSpherePaused = false;
GameStateManager.EnableMechaFunc = BulletTimePlugin.EnableMechaFunc.Value;
}
private static void OnFactoryLoadRequest(int planetId)
{
if (NebulaModAPI.MultiplayerSession.IsGameLoaded)
{
SendPacket(PauseEvent.FactoryRequest, planetId);
}
}
private static void OnFactoryLoadFinished(int planetId)
{
if (NebulaModAPI.MultiplayerSession.IsGameLoaded)
{
SendPacket(PauseEvent.FactoryLoaded, planetId);
}
}
public static void DetermineCurrentState()
{
if (LoadingPlayers.Count == 0 && !IsPlayerJoining)
{
if (GameStateManager.ManualPause)
{
GameStateManager.SetPauseMode(value: true);
GameStateManager.SetSyncingLock(isLock: false);
IngameUI.ShowStatus(BulletTimePlugin.StatusTextPause.Value);
SendPacket(PauseEvent.Pause);
}
else
{
GameStateManager.SetPauseMode(value: false);
GameStateManager.SetSyncingLock(isLock: false);
IngameUI.ShowStatus("");
SendPacket(PauseEvent.Resume);
}
}
else if (LoadingPlayers.Count > 0)
{
PauseNotificationPacket pauseNotificationPacket = new PauseNotificationPacket(PauseEvent.FactoryRequest, LoadingPlayers[0].username, LoadingPlayers[0].planetId);
NebulaModAPI.MultiplayerSession.Network.SendPacket<PauseNotificationPacket>(pauseNotificationPacket);
}
}
public static void SendPacket(PauseEvent pauseEvent, int planetId = 0)
{
string username = NebulaModAPI.MultiplayerSession.LocalPlayer.Data.Username;
NebulaModAPI.MultiplayerSession.Network.SendPacket<PauseNotificationPacket>(new PauseNotificationPacket(pauseEvent, username, planetId));
if (pauseEvent == PauseEvent.Resume)
{
LoadingPlayers.Clear();
IsPlayerJoining = false;
}
}
public static void SetPacketProcessing(bool enable)
{
Log.Info("SetPacketProcessing: " + enable);
NebulaModAPI.MultiplayerSession.Network.PacketProcessor.EnablePacketProcessing = enable;
}
}
public class NebulaPatch
{
private static int lastLength;
private static bool enablePingIndicatorUpdate = true;
[HarmonyPostfix]
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
private static void RealGameTick(ref long __result)
{
if (GameStateManager.StoredGameTick != 0L)
{
__result = GameStateManager.StoredGameTick;
}
}
[HarmonyPostfix]
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
private static void RealUPS(ref float __result)
{
if (!GameStateManager.Pause)
{
__result *= (1f - GameStateManager.SkipRatio) / 100f;
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(GameStatesManager), "NotifyTickDifference")]
private static void NotifyTickDifference(float delta)
{
if (!GameStateManager.Pause)
{
GameStateManager.SetSpeedRatio(Mathf.Clamp(1f + delta / (float)FPSController.currentUPS, 0.01f, 1f));
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(SimulatedWorld), "OnPlayerJoining")]
private static bool OnPlayerJoining(string username)
{
NebulaCompat.IsPlayerJoining = true;
GameMain.isFullscreenPaused = true;
IngameUI.ShowStatus(string.Format(Localization.Translate("{0} joining the game"), username));
GameStateManager.SetPauseMode(value: true);
GameStateManager.SetSyncingLock(isLock: true);
SetProgessMode(enable: true);
return false;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(SimulatedWorld), "OnAllPlayersSyncCompleted")]
private static void OnAllPlayersSyncCompleted()
{
NebulaCompat.IsPlayerJoining = false;
if (!NebulaCompat.IsClient)
{
NebulaCompat.DetermineCurrentState();
NebulaCompat.SendPacket(NebulaCompat.DysonSpherePaused ? PauseEvent.DysonSpherePaused : PauseEvent.DysonSphereResume);
}
SetProgessMode(enable: false);
}
[HarmonyPrefix]
[HarmonyPatch(typeof(GameSave), "SaveCurrentGame")]
private static void SaveCurrentGame_Prefix()
{
if (NebulaCompat.IsMultiplayerActive)
{
NebulaCompat.SendPacket(PauseEvent.Save);
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(GameSave), "SaveCurrentGame")]
private static void SaveCurrentGame_Postfix(string saveName)
{
if (NebulaCompat.IsMultiplayerActive && !NebulaCompat.IsClient)
{
if (saveName != GameSave.AutoSaveTmp)
{
NebulaCompat.LoadingPlayers.Clear();
NebulaCompat.IsPlayerJoining = false;
}
if (saveName != GameSave.saveExt)
{
NebulaCompat.DetermineCurrentState();
}
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(MechaLab), "GameTick")]
private static bool MechaLabGameTick_Prefix()
{
if (NebulaCompat.IsMultiplayerActive)
{
return !NebulaCompat.IsPlayerJoining;
}
return true;
}
[HarmonyPostfix]
[HarmonyPatch(typeof(UIDESphereInfo), "_OnInit")]
[HarmonyAfter(new string[] { "dsp.nebula-multiplayer" })]
private static void UIDESphereInfo__OnInit()
{
((Selectable)UIRoot.instance.uiGame.dysonEditor.controlPanel.topFunction.pauseButton.button).interactable = true;
SetDysonSpherePasued(NebulaCompat.DysonSpherePaused);
}
[HarmonyPrefix]
[HarmonyPatch(typeof(UIDETopFunction), "_OnLateUpdate")]
private static bool UIDETopFunction__OnLateUpdate()
{
return !NebulaCompat.IsMultiplayerActive;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(UIDETopFunction), "OnPauseButtonClick")]
private static bool OnPauseButtonClick()
{
if (NebulaCompat.IsMultiplayerActive)
{
SetDysonSpherePasued(!NebulaCompat.DysonSpherePaused);
NebulaCompat.SendPacket(NebulaCompat.DysonSpherePaused ? PauseEvent.DysonSpherePaused : PauseEvent.DysonSphereResume);
return false;
}
return true;
}
public static void SetDysonSpherePasued(bool state)
{
NebulaCompat.DysonSpherePaused = state;
UIDETopFunction topFunction = UIRoot.instance.uiGame.dysonEditor.controlPanel.topFunction;
topFunction.pauseButton.highlighted = !NebulaCompat.DysonSpherePaused;
topFunction.pauseImg.sprite = (NebulaCompat.DysonSpherePaused ? topFunction.pauseSprite : topFunction.playSprite);
topFunction.pauseText.text = Localization.Translate(NebulaCompat.DysonSpherePaused ? "Click to resume rotating" : "Click to stop rotating");
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(DysonSphereLayer), "GameTick")]
private static IEnumerable<CodeInstruction> DysonSphereLayer_GameTick(IEnumerable<CodeInstruction> instructions, ILGenerator iL)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Expected O, but got Unknown
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Expected O, but got Unknown
try
{
return new CodeMatcher(instructions, iL).MatchForward(true, (CodeMatch[])(object)new CodeMatch[2]
{
new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null),
new CodeMatch((OpCode?)OpCodes.Ldfld, (object)AccessTools.Field(typeof(DysonSphereLayer), "orbitAngularSpeed"), (string)null)
}).Repeat((Action<CodeMatcher>)delegate(CodeMatcher matcher)
{
matcher.SetAndAdvance(OpCodes.Call, (object)AccessTools.Method(typeof(NebulaPatch), "GetOrbitAngularSpeed", (Type[])null, (Type[])null));
}, (Action<string>)null).InstructionEnumeration();
}
catch (Exception obj)
{
Log.Error("DysonSphereLayer_GameTick Transpiler error");
Log.Error(obj);
return instructions;
}
}
private static float GetOrbitAngularSpeed(DysonSphereLayer @this)
{
if (!NebulaCompat.DysonSpherePaused)
{
return @this.orbitAngularSpeed;
}
return 0f;
}
[HarmonyPostfix]
[HarmonyPatch(typeof(GameStatesManager), "UpdateBufferLength")]
private static void UpdateBufferLength_Postfix(int length)
{
if (lastLength != length && GameStatesManager.FragmentSize > 0)
{
NebulaModAPI.MultiplayerSession.Network.SendPacket<ProgressUpdatePacket>(new ProgressUpdatePacket(GameStatesManager.FragmentSize, (float)length / (float)GameStatesManager.FragmentSize));
lastLength = length;
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(SimulatedWorld), "UpdatePingIndicator")]
private static bool UpdatePingIndicator_Prefix()
{
return enablePingIndicatorUpdate;
}
public static void SetProgessMode(bool enable)
{
if (enable)
{
enablePingIndicatorUpdate = false;
return;
}
enablePingIndicatorUpdate = true;
if (NebulaModAPI.MultiplayerSession.IsServer)
{
Multiplayer.Session.World.HidePingIndicator();
}
}
public static void SetProgressTest(int fragmentSize, float percentage)
{
bool num = enablePingIndicatorUpdate;
enablePingIndicatorUpdate = true;
Multiplayer.Session.World.UpdatePingIndicator($"Progress {fragmentSize / 1000:n0} KB ({percentage:P1})");
enablePingIndicatorUpdate = num;
}
}
internal class PauseNotificationPacket
{
public string Username { get; set; }
public PauseEvent Event { get; set; }
public int PlanetId { get; set; }
public PauseNotificationPacket()
{
}
public PauseNotificationPacket(PauseEvent pauseEvent, string username, int planetId = 0)
{
Event = pauseEvent;
Username = username;
PlanetId = planetId;
}
}
public enum PauseEvent
{
None,
Resume,
Pause,
Save,
FactoryRequest,
FactoryLoaded,
DysonSpherePaused,
DysonSphereResume
}
[RegisterPacketProcessor]
internal class PauseNotificationProcessor : BasePacketProcessor<PauseNotificationPacket>
{
public override void ProcessPacket(PauseNotificationPacket packet, INebulaConnection conn)
{
NebulaPatch.SetProgessMode(enable: false);
switch (packet.Event)
{
case PauseEvent.Resume:
if (base.IsHost)
{
if (GameStateManager.Interactable && GameStateManager.Pause)
{
IngameUI.OnKeyPause();
}
}
else
{
GameStateManager.ManualPause = false;
GameStateManager.SetPauseMode(value: false);
GameStateManager.SetSyncingLock(isLock: false);
IngameUI.SetHotkeyPauseMode(active: false);
IngameUI.ShowStatus("");
}
break;
case PauseEvent.Pause:
if (base.IsHost)
{
if (GameStateManager.Interactable && !GameStateManager.Pause)
{
IngameUI.OnKeyPause();
}
}
else
{
GameStateManager.ManualPause = true;
GameStateManager.SetPauseMode(value: true);
GameStateManager.SetSyncingLock(isLock: false);
IngameUI.SetHotkeyPauseMode(active: true);
}
break;
case PauseEvent.Save:
if (base.IsClient)
{
GameMain.isFullscreenPaused = true;
GameStateManager.SetPauseMode(value: true);
GameStateManager.SetSyncingLock(isLock: true);
IngameUI.ShowStatus(Localization.Translate("Host is saving game..."));
}
break;
case PauseEvent.FactoryRequest:
{
GameStateManager.SetPauseMode(value: true);
GameStateManager.SetSyncingLock(GameMain.localPlanet?.id == packet.PlanetId);
string format = Localization.Translate("{0} arriving {1}");
string username = packet.Username;
PlanetData obj = GameMain.galaxy.PlanetById(packet.PlanetId);
IngameUI.ShowStatus(string.Format(format, username, (obj != null) ? obj.displayName : null));
if (base.IsHost)
{
NebulaCompat.LoadingPlayers.Add((packet.Username, packet.PlanetId));
NebulaModAPI.MultiplayerSession.Network.SendPacket<PauseNotificationPacket>(packet);
}
NebulaPatch.SetProgessMode(packet.Username != NebulaModAPI.MultiplayerSession.LocalPlayer.Data.Username);
break;
}
case PauseEvent.FactoryLoaded:
if (base.IsHost)
{
NebulaCompat.LoadingPlayers.RemoveAll(((string username, int planetId) x) => x.username == packet.Username);
NebulaCompat.DetermineCurrentState();
}
break;
case PauseEvent.DysonSpherePaused:
NebulaPatch.SetDysonSpherePasued(state: true);
if (base.IsHost)
{
NebulaModAPI.MultiplayerSession.Network.SendPacket<PauseNotificationPacket>(packet);
}
break;
case PauseEvent.DysonSphereResume:
NebulaPatch.SetDysonSpherePasued(state: false);
if (base.IsHost)
{
NebulaModAPI.MultiplayerSession.Network.SendPacket<PauseNotificationPacket>(packet);
}
break;
}
}
}
internal class ProgressUpdatePacket
{
public int FragmentSize { get; set; }
public float Percentage { get; set; }
public ProgressUpdatePacket()
{
}
public ProgressUpdatePacket(int framentSize, float percentage)
{
FragmentSize = framentSize;
Percentage = percentage;
}
}
[RegisterPacketProcessor]
internal class ProgressUpdateProcessor : BasePacketProcessor<ProgressUpdatePacket>
{
public override void ProcessPacket(ProgressUpdatePacket packet, INebulaConnection conn)
{
if (base.IsHost)
{
NebulaModAPI.MultiplayerSession.Network.SendPacketExclude<ProgressUpdatePacket>(packet, conn);
Multiplayer.Session.World.DisplayPingIndicator();
}
NebulaPatch.SetProgressTest(packet.FragmentSize, packet.Percentage);
}
}
internal class IngameUI
{
public static string CurrentStatus = "";
private static Slider slider;
private static Text sliderText;
private static Text stateMessage;
private static UIToggle backgroundSaveToggle;
private static GameObject timeTextGo;
private static GameObject infoTextGo;
private static Text speedRatioText;
private static readonly GameObject[] speedBtnGo = (GameObject[])(object)new GameObject[3];
public static void Dispose()
{
if ((Object)(object)slider != (Object)null)
{
((UnityEventBase)slider.onValueChanged).RemoveAllListeners();
Object.Destroy((Object)(object)((Component)slider).gameObject);
}
slider = null;
sliderText = null;
if ((Object)(object)stateMessage != (Object)null)
{
Object.Destroy((Object)(object)((Component)((Component)stateMessage).transform.GetParent()).gameObject);
stateMessage = null;
}
if ((Object)(object)backgroundSaveToggle != (Object)null)
{
Object.Destroy((Object)(object)((Component)((Component)backgroundSaveToggle).transform.parent).gameObject);
backgroundSaveToggle = null;
}
timeTextGo = null;
for (int i = 0; i < speedBtnGo.Length; i++)
{
Object.Destroy((Object)(object)speedBtnGo[i]);
speedBtnGo[i] = null;
}
Object.Destroy((Object)(object)infoTextGo);
infoTextGo = null;
Text obj = speedRatioText;
Object.Destroy((Object)(object)((obj != null) ? ((Component)obj).gameObject : null));
speedRatioText = null;
}
public static void Init()
{
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_016a: Unknown result type (might be due to invalid IL or missing references)
//IL_01bf: 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_027d: Unknown result type (might be due to invalid IL or missing references)
//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
//IL_02db: Unknown result type (might be due to invalid IL or missing references)
//IL_054e: Unknown result type (might be due to invalid IL or missing references)
//IL_055d: Unknown result type (might be due to invalid IL or missing references)
//IL_0562: Unknown result type (might be due to invalid IL or missing references)
try
{
if ((Object)(object)slider == (Object)null)
{
GameObject gameObject = ((Component)((Component)UIRoot.instance.optionWindow.audioVolumeComp).transform).gameObject;
Transform parent = ((Component)UIRoot.instance.uiGame.statWindow.performancePanelUI.cpuActiveButton).gameObject.transform.parent;
GameObject obj = Object.Instantiate<GameObject>(gameObject, parent);
((Object)obj).name = "RealTickRatioSlider";
obj.transform.localPosition = parent.Find("title-text").localPosition + new Vector3(-120f, 1f, 0f);
slider = obj.GetComponent<Slider>();
sliderText = obj.GetComponentInChildren<Text>();
slider.value = BulletTimePlugin.StartingSpeed.Value;
((UnityEvent<float>)(object)slider.onValueChanged).AddListener((UnityAction<float>)delegate(float value)
{
OnSliderChange(value);
});
OnSliderChange(slider.value);
GameObject gameObject2 = ((Component)((Component)UIRoot.instance.optionWindow.fullscreenComp).transform.parent).gameObject;
Transform parent2 = ((Component)UIRoot.instance.uiGame.statWindow.performancePanelUI.dataActiveButton).gameObject.transform.parent;
GameObject obj2 = Object.Instantiate<GameObject>(gameObject2, parent2);
((Object)obj2).name = "Background autosave toggle";
obj2.transform.localPosition = new Vector3(250f, 390f, 0f);
Object.Destroy((Object)(object)obj2.GetComponent<Localizer>());
Text component = obj2.GetComponent<Text>();
component.fontSize = 14;
component.text = Localization.Translate("Background autosave");
backgroundSaveToggle = obj2.GetComponentInChildren<UIToggle>();
((Component)backgroundSaveToggle).transform.localPosition = new Vector3(65f, -20f, 0f);
backgroundSaveToggle.isOn = GameSave_Patch.isEnabled;
((UnityEvent<bool>)(object)backgroundSaveToggle.toggle.onValueChanged).AddListener((UnityAction<bool>)OnAutosaveToggleChange);
}
((Component)slider).gameObject.SetActive(!NebulaCompat.IsClient);
GameStateManager.ManualPause = false;
SetHotkeyPauseMode(active: false);
}
catch (Exception ex)
{
Log.Warn("IngameUI fail! error:\n" + ex);
}
try
{
if ((Object)(object)timeTextGo == (Object)null)
{
timeTextGo = GameObject.Find("UI Root/Overlay Canvas/In Game/Game Menu/time-text");
timeTextGo.SetActive(true);
RectTransform component2 = GameObject.Find("UI Root/Overlay Canvas/In Game/Game Menu/button-1-bg").GetComponent<RectTransform>();
Vector3 localPosition = ((Transform)component2).localPosition;
localPosition.x += 35f;
localPosition.y -= 20f;
for (int i = 0; i < 3; i++)
{
RectTransform val = Object.Instantiate<RectTransform>(component2, timeTextGo.transform.parent);
((Transform)val).localScale = new Vector3(0.35f, 0.35f, 0.35f);
((Transform)val).localPosition = localPosition;
localPosition.x += 22f;
UIButton component3 = ((Component)val).GetComponent<UIButton>();
component3.OnPointerDown((PointerEventData)null);
component3.OnPointerEnter((PointerEventData)null);
component3.data = i;
component3.onClick += OnSpeedButtonClick;
Sprite sprite = null;
switch (i)
{
case 0:
{
sprite = ((Component)((Component)UIRoot.instance.uiGame.researchQueue.pauseButton).gameObject.transform.Find("icon")).GetComponent<Image>().sprite;
ref TipSettings tips3 = ref component3.tips;
string tipTitle = (((Object)val).name = Localization.Translate("Pause"));
tips3.tipTitle = tipTitle;
component3.tips.tipText = Localization.Translate("Toggle tactical pause mode");
break;
}
case 1:
{
sprite = ((Component)((Component)UIRoot.instance.uiGame.researchQueue.resumeButton).gameObject.transform.Find("icon")).GetComponent<Image>().sprite;
ref TipSettings tips2 = ref component3.tips;
string tipTitle = (((Object)val).name = Localization.Translate("Resume"));
tips2.tipTitle = tipTitle;
component3.tips.tipText = Localization.Translate("Reset game speed back to 1x");
break;
}
case 2:
{
sprite = Resources.Load<Sprite>("ui/textures/sprites/test/next-icon-2");
ref TipSettings tips = ref component3.tips;
string tipTitle = (((Object)val).name = Localization.Translate("SpeedUp"));
tips.tipTitle = tipTitle;
component3.tips.tipText = string.Format(Localization.Translate("Left click to increase game speed\nRight click to set to max ({0}x)"), BulletTimePlugin.MaxSpeedupScale.Value);
component3.onRightClick += OnSpeedupButtonRightClcik;
break;
}
}
((Component)((Transform)val).Find("button-1/icon")).GetComponent<Image>().sprite = sprite;
speedBtnGo[i] = ((Component)val).gameObject;
}
infoTextGo = Object.Instantiate<GameObject>(timeTextGo, timeTextGo.transform.parent);
((Object)infoTextGo).name = "pause info-text";
infoTextGo.GetComponent<Text>().text = Localization.Translate("Pause");
((Behaviour)infoTextGo.GetComponent<Text>()).enabled = true;
infoTextGo.SetActive(false);
GameObject obj3 = GameObject.Find("UI Root/Overlay Canvas/In Game/Game Menu/real-time-text");
GameObject obj4 = Object.Instantiate<GameObject>(obj3, obj3.transform.parent);
((Object)obj4).name = "speed ratio-text";
Transform transform = obj4.transform;
transform.localPosition += new Vector3(0f, 15f);
obj4.SetActive(true);
speedRatioText = obj4.GetComponent<Text>();
}
speedBtnGo[2].SetActive(!NebulaCompat.IsClient);
SetSpeedRatioText();
}
catch (Exception ex2)
{
Log.Warn("Game Menu button UI fail! error:\n" + ex2);
}
}
private static void OnSpeedButtonClick(int mode)
{
switch (mode)
{
case 0:
OnKeyPause();
break;
case 1:
FPSController.SetFixUPS(0.0);
if (GameStateManager.Pause)
{
OnKeyPause();
}
break;
case 2:
if (GameStateManager.Pause)
{
OnKeyPause();
}
else if (FPSController.instance.fixUPS == 0.0)
{
FPSController.SetFixUPS(120.0);
}
else if (FPSController.instance.fixUPS < 60.0 * (double)BulletTimePlugin.MaxSpeedupScale.Value)
{
FPSController.SetFixUPS(FPSController.instance.fixUPS + 60.0);
}
break;
}
SetSpeedRatioText();
}
private static void OnSpeedupButtonRightClcik(int _)
{
if (GameStateManager.Pause)
{
OnKeyPause();
}
FPSController.SetFixUPS(60.0 * (double)BulletTimePlugin.MaxSpeedupScale.Value);
SetSpeedRatioText();
}
private static void SetSpeedRatioText()
{
if ((Object)(object)speedRatioText == (Object)null)
{
return;
}
if (NebulaCompat.IsClient)
{
speedRatioText.text = "";
return;
}
float num = (float)FPSController.instance.fixUPS / 60f;
if (num == 0f)
{
speedRatioText.text = "1 x";
}
else if ((double)(num - (float)(int)num) < 0.05)
{
speedRatioText.text = (int)num + " x";
}
else
{
speedRatioText.text = $"{num:0.0} x";
}
}
public static void OnPauseModeChange(bool pause)
{
if ((Object)(object)infoTextGo != (Object)null)
{
timeTextGo.SetActive(!pause);
infoTextGo.SetActive(pause);
if ((Object)(object)sliderText != (Object)null)
{
sliderText.text = (pause ? Localization.Translate("Pause") : $"{(int)slider.value}%");
}
SetSpeedRatioText();
}
SetHotkeyPauseMode(active: false);
}
private static void OnSliderChange(float value)
{
if (value == 0f)
{
GameStateManager.ManualPause = true;
sliderText.text = Localization.Translate("pause");
if (!GameStateManager.Pause && NebulaCompat.IsMultiplayerActive)
{
NebulaCompat.SendPacket(PauseEvent.Pause);
}
}
else
{
GameStateManager.ManualPause = false;
sliderText.text = $"{(int)value}%";
if (GameStateManager.Pause && NebulaCompat.IsMultiplayerActive)
{
NebulaCompat.SendPacket(PauseEvent.Resume);
}
ShowStatus("");
}
GameStateManager.SetSpeedRatio(value / 100f);
SetHotkeyPauseMode(active: false);
}
public static void SetHotkeyPauseMode(bool active)
{
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
GameStateManager.HotkeyPause = active;
if (active)
{
if (NebulaCompat.IsMultiplayerActive && !NebulaCompat.IsClient)
{
NebulaCompat.SendPacket(PauseEvent.Pause);
}
Player mainPlayer = GameMain.mainPlayer;
GameStateManager.PlayerPosition = ((mainPlayer != null) ? mainPlayer.position : Vector3.zero);
SkillSystem_Patch.Enable = GameStateManager.EnableMechaFunc;
ShowStatus(BulletTimePlugin.StatusTextPause.Value);
}
else
{
SkillSystem_Patch.Enable = false;
}
}
public static void OnKeyPause()
{
if (NebulaCompat.IsClient)
{
if (GameStateManager.Interactable)
{
if (!GameStateManager.Pause)
{
NebulaCompat.SendPacket(PauseEvent.Pause);
}
else
{
NebulaCompat.SendPacket(PauseEvent.Resume);
}
}
}
else if (!GameStateManager.Pause)
{
if (UIRoot.instance.uiGame.autoSave.showTime == 0f)
{
GameStateManager.ManualPause = true;
GameStateManager.SetPauseMode(value: true);
SetHotkeyPauseMode(active: true);
}
}
else if (GameStateManager.Interactable)
{
OnSliderChange(slider.value);
}
}
private static void OnAutosaveToggleChange(bool val)
{
GameSave_Patch.Enable(val);
backgroundSaveToggle.isOn = val;
}
public static void ShowStatus(string message)
{
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)stateMessage == (Object)null)
{
GameObject obj = GameObject.Find("UI Root/Overlay Canvas/In Game/Top Tips/Auto Save/content/tip-panel");
GameObject val = Object.Instantiate<GameObject>(obj, obj.transform.parent.parent);
val.transform.localPosition = new Vector3(-35f, val.transform.localPosition.y + (float)BulletTimePlugin.StatusTextHeightOffset.Value, 0f);
Object.Destroy((Object)(object)((Component)val.transform.Find("bg")).gameObject);
Object.Destroy((Object)(object)((Component)val.transform.Find("icon")).gameObject);
Object.Destroy((Object)(object)((Component)val.transform.Find("glow-1")).gameObject);
Object.Destroy((Object)(object)((Component)val.transform.Find("achiev-ban-text")).gameObject);
stateMessage = ((Component)val.transform.Find("text")).GetComponent<Text>();
}
((Component)((Component)stateMessage).transform.GetParent()).gameObject.SetActive(message != "");
stateMessage.text = message;
CurrentStatus = message;
}
}
internal class GameSave_Patch
{
public static bool isBlocked = false;
public static bool isEnabled = false;
private static Harmony harmony = null;
private static readonly AutoResetEvent autoEvent = new AutoResetEvent(initialState: false);
public static void Enable(bool enable)
{
if (NebulaCompat.NebulaIsInstalled)
{
isEnabled = enable;
return;
}
if (enable && harmony == null)
{
Log.Debug("Patch GameSave_Patch");
harmony = Harmony.CreateAndPatchAll(typeof(GameSave_Patch), (string)null);
isEnabled = true;
}
if (!enable && harmony != null)
{
Log.Debug("Unpatch GameSave_Patch");
harmony.UnpatchSelf();
harmony = null;
isEnabled = false;
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(UIGame), "_OnUpdate")]
private static void UIGame_Prefix(UIGame __instance)
{
if (!GameMain.isRunning || __instance.willClose || GameStateManager.Interactable || isBlocked)
{
return;
}
bool num = ((ManualBehaviour)__instance.dysonEditor).active || (GameStateManager.LockFactory && __instance.isAnyFunctionWindowActive);
bool flag = ((ManualBehaviour)__instance.statWindow).active || ((ManualBehaviour)__instance.replicator).active || ((ManualBehaviour)__instance.mechaWindow).active || ((ManualBehaviour)__instance.blueprintBrowser).active;
if (!num || flag)
{
return;
}
if (((ManualBehaviour)__instance.dysonEditor).active)
{
if (string.IsNullOrEmpty(IngameUI.CurrentStatus))
{
ShowMessage(Localization.Translate("Read-Only"), Localization.Translate("Can't interact with game world during auto-save\nPlease wait or press ESC to close the window"));
}
else
{
ShowMessage(Localization.Translate("Read-Only"), Localization.Translate("Can't interact with game world when player is loading the game"));
}
}
else
{
ShowMessage();
}
isBlocked = true;
}
private static void ShowMessage(string title = null, string message = null)
{
//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
UIDialog obj = UIDialog.CreateDialog("Prefabs/MessageBox VE");
UIMessageBox val = (UIMessageBox)(object)((obj is UIMessageBox) ? obj : null);
if (title != null && message != null)
{
val.m_TitleText.text = title;
val.m_MessageText.text = message;
((Component)((Component)val.m_Button1).transform.parent).gameObject.SetActive(false);
((Component)((Component)val.m_Button2).transform.parent).gameObject.SetActive(false);
((Component)((Component)val.m_Button3).transform.parent).gameObject.SetActive(false);
((Component)val.m_IconImage).gameObject.SetActive(false);
}
else
{
((Component)val.m_WindowTrans).gameObject.SetActive(false);
((Graphic)((Component)val).gameObject.GetComponent<Image>()).color = Color.clear;
}
UIMessageBox.PushMessage(val);
}
[HarmonyPostfix]
[HarmonyPatch(typeof(UIMessageBox), "CloseTopMessage")]
private static void CloseTopMessage_Postfix(ref bool __result)
{
if (isBlocked)
{
__result = false;
isBlocked = false;
}
}
[HarmonyPostfix]
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
private static void BuildConfirm_Postfix(ref InputValue __result)
{
if (GameStateManager.LockFactory)
{
__result.onUp = false;
__result.onDown = false;
}
}
[HarmonyPostfix]
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
private static void InstantConstruct_Postfix(ref bool __result)
{
if (GameStateManager.LockFactory)
{
__result = false;
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(UIAutoSave), "_OnLateUpdate")]
private static bool AutoSaveGuard(UIAutoSave __instance)
{
if (__instance.showTime == 0f && GameStateManager.Pause)
{
return false;
}
return true;
}
[HarmonyPostfix]
[HarmonyPatch(typeof(UIAutoSave), "_OnLateUpdate")]
private static void OverwriteSaveText(UIAutoSave __instance)
{
if (GameStateManager.IsSaving)
{
__instance.saveText.text = Localization.Translate("Saving...");
__instance.showTime = 1.8f;
}
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(UIAutoSave), "_OnLateUpdate")]
public static IEnumerable<CodeInstruction> RemoveGC_Transpiler(IEnumerable<CodeInstruction> instructions)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: Expected O, but got Unknown
return new CodeMatcher(instructions, (ILGenerator)null).End().MatchBack(false, (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(GameSave), "AutoSave", (Type[])null, (Type[])null), (string)null)
}).SetOperandAndAdvance((object)AccessTools.Method(typeof(GameSave_Patch), "AsyncAutoSave", (Type[])null, (Type[])null))
.InstructionEnumeration();
}
private static bool AsyncAutoSave()
{
if (!isEnabled)
{
return GameSave.AutoSave();
}
GameCamera.CaptureSaveScreenShot();
bool tmp = GameStateManager.Pause;
bool isFullscreenPaused = GameMain.isFullscreenPaused;
if (NebulaCompat.IsMultiplayerActive)
{
GameMain.isFullscreenPaused = true;
NebulaCompat.SetPacketProcessing(enable: false);
}
GameStateManager.SetPauseMode(value: true);
GameStateManager.SetInteractable(value: false);
GameStateManager.IsSaving = true;
ThreadingHelper.Instance.StartAsyncInvoke((Func<Action>)delegate
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Expected O, but got Unknown
HighStopwatch val = new HighStopwatch();
val.Begin();
Thread.Sleep((int)(1000.0 / FPSController.currentUPS));
Log.Info($"Background Autosave start. UPS: {FPSController.currentUPS:F2}");
bool result = GameSave.AutoSave();
Log.Info($"Background Autosave end. Duration: {val.duration}s");
return delegate
{
GC.Collect();
GameStateManager.IsSaving = false;
GameStateManager.SetInteractable(value: true);
GameStateManager.SetPauseMode(tmp);
GameMain.isFullscreenPaused = isFullscreenPaused;
if (NebulaCompat.IsMultiplayerActive)
{
NebulaCompat.SetPacketProcessing(enable: true);
}
UIRoot.instance.uiGame.autoSave.saveText.text = (result ? Localization.Translate("保存成功") : Localization.Translate("保存失败"));
UIRoot.instance.uiGame.autoSave.contentTweener.Play1To0();
};
});
return false;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(GameCamera), "CaptureSaveScreenShot")]
private static bool CaptureSaveScreenShot_Prefix()
{
if (!GameStateManager.Interactable)
{
return false;
}
return true;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(DysonSwarm), "Export")]
private static bool Export_Prefix(DysonSwarm __instance, BinaryWriter w)
{
if (!GameStateManager.Interactable && ThreadingHelper.Instance.InvokeRequired)
{
autoEvent.Reset();
ThreadingHelper.Instance.StartSyncInvoke((Action)delegate
{
__instance.Export(w);
autoEvent.Set();
});
autoEvent.WaitOne(-1);
return false;
}
return true;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(SpaceSector), "EndSave")]
private static bool SpaceSectorEndSave_Prefix(SpaceSector __instance)
{
if (!GameStateManager.Interactable && ThreadingHelper.Instance.InvokeRequired)
{
autoEvent.Reset();
ThreadingHelper.Instance.StartSyncInvoke((Action)delegate
{
__instance.EndSave();
autoEvent.Set();
});
autoEvent.WaitOne(-1);
return false;
}
return true;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(Player), "Export")]
private static void Player_Prefix()
{
if (!GameStateManager.Interactable)
{
Monitor.Enter(GameMain.data.mainPlayer);
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Player), "Export")]
private static void Player_Postfix()
{
if (!GameStateManager.Interactable)
{
Monitor.Exit(GameMain.data.mainPlayer);
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(PlanetFactory), "Export")]
private static void PlanetFactory_Prefix(PlanetFactory __instance)
{
if (!GameStateManager.Interactable && __instance.planetId == GameMain.localPlanet?.id)
{
GameStateManager.SetLockFactory(value: true);
Thread.Sleep((int)Maths.Clamp(1000.0 / FPSController.currentUPS, 17.0, 1000.0));
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(PlanetFactory), "Export")]
private static void PlanetFactory_Postfix(PlanetFactory __instance)
{
if (!GameStateManager.Interactable && __instance.planetId == GameMain.localPlanet?.id)
{
GameStateManager.SetLockFactory(value: false);
}
}
}
internal class GameMain_Patch
{
private static bool pasueThisFrame;
[HarmonyPrefix]
[HarmonyPatch(typeof(GameMain), "FixedUpdate")]
private static bool FixedUpdate_Prefix(GameMain __instance)
{
if ((!GameMain.isRunning || GameMain.isPaused) && !NebulaCompat.IsMultiplayerActive)
{
return true;
}
pasueThisFrame = GameStateManager.PauseInThisFrame();
if (!pasueThisFrame)
{
return true;
}
if (GameStateManager.AdvanceTick)
{
__instance.timei++;
__instance.timei_once++;
}
__instance.timef = (double)__instance.timei * (1.0 / 60.0);
__instance.timef_once = (double)__instance.timei_once * (1.0 / 60.0);
GameData data = GameMain.data;
PerformanceMonitor.BeginLogicFrame();
PerformanceMonitor.BeginSample((ECpuWorkEntry)2);
PerformanceMonitor.BeginSample((ECpuWorkEntry)3);
bool num = !__instance.isMenuDemo && data.DetermineLocalPlanet();
data.DetermineRelative();
__instance.SetStarmapReferences(GameMain.data);
if (num)
{
GameCamera.instance.FrameLogic();
}
VFInput.UpdateGameStates();
Player mainPlayer = GameMain.mainPlayer;
if (mainPlayer != null && mainPlayer.controller.actionSail.fastTravelling)
{
GameMain.universeSimulator.GameTick(__instance.timef);
data.DetermineRelative();
PerformanceMonitor.EndSample((ECpuWorkEntry)3);
}
else
{
UniverseSimulatorGameTick();
PerformanceMonitor.EndSample((ECpuWorkEntry)3);
PerformanceMonitor.BeginSample((ECpuWorkEntry)31);
data.mainPlayer.packageUtility.Count();
PerformanceMonitor.EndSample((ECpuWorkEntry)31);
if (GameMain.localPlanet != null && GameMain.localPlanet.factoryLoaded)
{
PerformanceMonitor.BeginSample((ECpuWorkEntry)42);
GameMain.localPlanet.factory.cargoTraffic.ClearStates();
GameMain.localPlanet.physics.GameTick();
PerformanceMonitor.EndSample((ECpuWorkEntry)42);
}
if (data.spaceSector != null)
{
PerformanceMonitor.BeginSample((ECpuWorkEntry)42);
if (!DSPGame.IsMenuDemo)
{
data.spaceSector.physics.GameTick();
}
PerformanceMonitor.EndSample((ECpuWorkEntry)42);
}
if (data.guideMission != null)
{
PerformanceMonitor.BeginSample((ECpuWorkEntry)4);
data.guideMission.GameTick();
PerformanceMonitor.EndSample((ECpuWorkEntry)4);
}
if (GameMain.mainPlayer != null)
{
PerformanceMonitor.BeginSample((ECpuWorkEntry)7);
data.mainPlayer.ApplyGamePauseState(false);
PlayerGameTick(__instance.timei);
data.DetermineRelative();
PerformanceMonitor.EndSample((ECpuWorkEntry)7);
}
if (data.spaceSector != null)
{
if (GameStateManager.Interactable)
{
SkillSystem_Patch.GameTick(data.spaceSector.skillSystem);
}
PerformanceMonitor.BeginSample((ECpuWorkEntry)42);
data.spaceSector.model.PostGameTick();
if (!DSPGame.IsMenuDemo)
{
data.spaceSector.physics.PostGameTick();
}
PerformanceMonitor.EndSample((ECpuWorkEntry)42);
}
if (data.localPlanet != null && data.localPlanet.factoryLoaded)
{
PerformanceMonitor.BeginSample((ECpuWorkEntry)43);
data.localPlanet.audio.GameTick();
PerformanceMonitor.EndSample((ECpuWorkEntry)43);
}
}
PerformanceMonitor.EndSample((ECpuWorkEntry)2);
PerformanceMonitor.EndLogicFrame();
return false;
}
[HarmonyPostfix]
[HarmonyPatch(typeof(GameMain), "FixedUpdate")]
private static void FixedUpdate_Postfix()
{
if (pasueThisFrame)
{
pasueThisFrame = false;
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(GameMain), "Begin")]
private static void Begin_Postfix()
{
if (!GameMain.instance.isMenuDemo)
{
IngameUI.Init();
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(GameMain), "End")]
private static void End_Postfix()
{
IngameUI.Dispose();
GameStateManager.SetSpeedRatio(1f);
}
[HarmonyPrefix]
[HarmonyPatch(typeof(GameSave), "SaveCurrentGame")]
private static void SaveCurrentGame_Prefix()
{
if (GameStateManager.StoredGameTick != 0L)
{
GameMain.gameTick = GameStateManager.StoredGameTick;
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(PlayerAnimator), "GamePauseLogic")]
private static bool GamePauseLogic_Prefix(PlayerAnimator __instance, ref bool __result)
{
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
if (!GameStateManager.Pause)
{
return true;
}
if (GameStateManager.HotkeyPause && !GameStateManager.EnableMechaFunc)
{
__instance.PauseAllAnimations();
__instance.motorBone.localPosition = Vector3.zero;
__result = true;
return false;
}
__result = false;
return false;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(ABN_MechaPosition), "OnGameTick")]
private static bool ABN_MechaPosition_Prefix()
{
return false;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(UIStarmap), "StartFastTravelToPlanet")]
private static bool StartFastTravelToPlanet_Prefix()
{
if (GameMain.isFullscreenPaused)
{
UIRealtimeTip.Popup("Can't teleport to another planet during BulletTime pause!", true, 0);
return false;
}
return true;
}
private static void UniverseSimulatorGameTick()
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: 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_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_006c: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: 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_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: 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_00a9: Unknown result type (might be due to invalid IL or missing references)
//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
UniverseSimulator universeSimulator = GameMain.universeSimulator;
((Component)universeSimulator.backgroundStars).transform.position = ((Component)Camera.main).transform.position;
if (GameMain.localPlanet != null)
{
((Component)universeSimulator.backgroundStars).transform.rotation = Quaternion.Inverse(GameMain.localPlanet.runtimeRotation);
}
else
{
((Component)universeSimulator.backgroundStars).transform.rotation = Quaternion.identity;
}
Vector3 position = GameMain.mainPlayer.position;
VectorLF3 uPosition = GameMain.mainPlayer.uPosition;
Vector3 position2 = ((Component)GameCamera.main).transform.position;
Quaternion rotation = ((Component)GameCamera.main).transform.rotation;
for (int i = 0; i < universeSimulator.starSimulators.Length; i++)
{
universeSimulator.starSimulators[i].UpdateUniversalPosition(position, uPosition, position2, rotation);
}
if (universeSimulator.planetSimulators == null)
{
return;
}
for (int j = 0; j < universeSimulator.planetSimulators.Length; j++)
{
if ((Object)(object)universeSimulator.planetSimulators[j] != (Object)null)
{
universeSimulator.planetSimulators[j].UpdateUniversalPosition(uPosition, position2);
}
}
}
private static void PlayerGameTick(long time)
{
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
Player mainPlayer = GameMain.data.mainPlayer;
if (mainPlayer == null)
{
return;
}
if (GameStateManager.HotkeyPause)
{
if (GameStateManager.EnableMechaFunc)
{
mainPlayer.GameTick(time);
return;
}
mainPlayer.controller.SetCommandStateHeader();
mainPlayer.controller.UpdateCommandState();
mainPlayer.controller.GetInput();
mainPlayer.controller.HandleBaseInput();
((PlayerAction)mainPlayer.controller.actionRts).GameTick(time);
((PlayerAction)mainPlayer.controller.actionBuild).GameTick(time);
((PlayerAction)mainPlayer.controller.actionInspect).GameTick(time);
mainPlayer.controller.ClearForce();
mainPlayer.position = GameStateManager.PlayerPosition;
mainPlayer.gizmo.GameTick();
mainPlayer.orders.GameTick(time);
}
else if (GameStateManager.Interactable)
{
mainPlayer.GameTick(time);
}
else
{
Monitor.Enter(mainPlayer);
mainPlayer.mecha.GenerateEnergy(1.0 / 60.0);
if (mainPlayer.controller.cmd.raycast != null)
{
mainPlayer.controller.cmd.raycast.castVege.id = 0;
mainPlayer.controller.cmd.raycast.castVein.id = 0;
}
mainPlayer.controller.GameTick(time);
mainPlayer.gizmo.GameTick();
mainPlayer.orders.GameTick(time);
mainPlayer.mecha.forge.GameTick(time, 1f / 60f);
mainPlayer.mecha.UpdateSkillColliders();
Monitor.Exit(mainPlayer);
}
}
}
public static class GameStateManager
{
private static float timer;
public static bool Pause { get; private set; }
public static bool ManualPause { get; set; }
public static bool HotkeyPause { get; set; }
public static bool EnableMechaFunc { get; set; }
public static bool IsSaving { get; set; }
public static bool AdvanceTick { get; private set; } = true;
public static long StoredGameTick { get; private set; }
public static bool Interactable { get; private set; } = true;
public static bool LockFactory { get; private set; } = false;
public static float SkipRatio { get; private set; }
public static Vector3 PlayerPosition { get; set; }
public static void SetSpeedRatio(float value)
{
if (value == 0f)
{
SetPauseMode(value: true);
SkipRatio = 1f;
return;
}
if (Pause)
{
SetPauseMode(value: false);
}
SkipRatio = 1f - value;
timer = 0f;
}
public static void SetPauseMode(bool value)
{
if (value)
{
Pause = true;
if (StoredGameTick == 0L)
{
StoredGameTick = GameMain.gameTick;
Log.Debug($"Enter pause mode, gameTick = {StoredGameTick}");
if (NebulaCompat.IsClient)
{
FPSController.SetFixUPS(0.0);
}
}
}
else
{
Pause = false;
if (StoredGameTick != 0L)
{
Log.Debug($"Exit pause mode, duration: {GameMain.gameTick - StoredGameTick} ticks.");
GameMain.gameTick = StoredGameTick;
StoredGameTick = 0L;
}
GameMain.isFullscreenPaused = false;
SetLockFactory(value: false);
}
IngameUI.OnPauseModeChange(value);
}
public static bool PauseInThisFrame()
{
bool result = Pause;
AdvanceTick = GameMain.data.guideComplete && Interactable;
if (HotkeyPause && !EnableMechaFunc)
{
AdvanceTick = false;
}
if (!Pause)
{
timer += SkipRatio;
if (timer >= 1f)
{
timer -= 1f;
result = true;
AdvanceTick = false;
}
}
return result;
}
public static void SetInteractable(bool value)
{
Interactable = value;
if (Interactable && GameSave_Patch.isBlocked)
{
GameSave_Patch.isBlocked = false;
UIMessageBox.CloseTopMessage();
}
}
public static void SetLockFactory(bool value)
{
LockFactory = value;
if (!LockFactory && !((ManualBehaviour)UIRoot.instance.uiGame.dysonEditor).active && GameSave_Patch.isBlocked)
{
GameSave_Patch.isBlocked = false;
UIMessageBox.CloseTopMessage();
}
}
public static void SetSyncingLock(bool isLock)
{
SetInteractable(!isLock);
SetLockFactory(isLock);
Log.Debug("SetSyncingLock: " + isLock);
}
}
[BepInPlugin("com.starfi5h.plugin.BulletTime", "BulletTime", "1.5.2")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class BulletTimePlugin : BaseUnityPlugin
{
public const string GUID = "com.starfi5h.plugin.BulletTime";
public const string NAME = "BulletTime";
public const string VERSION = "1.5.2";
public static ConfigEntry<bool> EnableBackgroundAutosave;
public static ConfigEntry<bool> EnableFastLoading;
public static ConfigEntry<bool> RemoveGC;
public static ConfigEntry<float> StartingSpeed;
public static ConfigEntry<KeyboardShortcut> KeyAutosave;
public static ConfigEntry<KeyCode> KeyPause;
public static ConfigEntry<int> StatusTextHeightOffset;
public static ConfigEntry<string> StatusTextPause;
public static ConfigEntry<bool> EnableMechaFunc;
public static ConfigEntry<int> MaxSpeedupScale;
private static Harmony harmony;
private void LoadConfig()
{
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_0106: Unknown result type (might be due to invalid IL or missing references)
//IL_0110: Expected O, but got Unknown
KeyAutosave = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hotkey", "KeyAutosave", new KeyboardShortcut((KeyCode)291, (KeyCode[])(object)new KeyCode[1] { (KeyCode)304 }), "Keyboard shortcut for auto-save\n自动存档的热键组合");
KeyPause = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Hotkey", "KeyPause", (KeyCode)19, "Hotkey for toggling special pause mode\n特殊时停模式的热键");
EnableMechaFunc = ((BaseUnityPlugin)this).Config.Bind<bool>("Pause", "EnableMechaFunc", false, "Enable mecha function in hotkey pause mode\n在热键暂停模式下启用机甲功能");
EnableBackgroundAutosave = ((BaseUnityPlugin)this).Config.Bind<bool>("Save", "EnableBackgroundAutosave", false, "Do auto-save in background thread\n在背景执行自动存档");
EnableFastLoading = ((BaseUnityPlugin)this).Config.Bind<bool>("Speed", "EnableFastLoading", true, "Increase main menu loading speed\n加快载入主选单");
RemoveGC = ((BaseUnityPlugin)this).Config.Bind<bool>("Speed", "RemoveGC", true, "Remove force garbage collection of build tools\n移除建筑工具的强制内存回收");
StartingSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Speed", "StartingSpeed", 100f, new ConfigDescription("Game speed when the game begin (0-100)\n游戏开始时的游戏速度 (0-100)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
StatusTextHeightOffset = ((BaseUnityPlugin)this).Config.Bind<int>("UI", "StatusTextHeightOffset", 100, "Height of Status text relative to auto save text\n状态提示相对于自动保存提示的高度");
StatusTextPause = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "StatusTextPause", "Bullet Time", "Status text when in pause mode\n暂停时的状态提示文字");
MaxSpeedupScale = ((BaseUnityPlugin)this).Config.Bind<int>("UI", "MaxSpeedupScale", 10, "Maximum game speed multiplier for speedup button\n加速按钮的最大游戏速度倍率");
if (MaxSpeedupScale.Value <= 0)
{
MaxSpeedupScale.Value = 1;
}
GameStateManager.EnableMechaFunc = EnableMechaFunc.Value;
}
public void Start()
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Expected O, but got Unknown
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
if (GameConfig.gameVersion.Major == 0 && GameConfig.gameVersion.Minor < 10)
{
throw new Exception("BulletTime 1.5.2 only support 0.10.x game version!\nPlease roll back to BulletTime 1.2.14 for 0.9.x game version");
}
Log.Init(((BaseUnityPlugin)this).Logger);
harmony = new Harmony("com.starfi5h.plugin.BulletTime");
LoadConfig();
try
{
if (Chainloader.PluginInfos.ContainsKey("dsp.nebula-multiplayer"))
{
NebulaCompat.Init(harmony);
}
harmony.PatchAll(typeof(GameMain_Patch));
harmony.PatchAll(typeof(IngameUI));
if (NebulaCompat.NebulaIsInstalled)
{
harmony.PatchAll(typeof(GameSave_Patch));
GameSave_Patch.Enable(enable: true);
}
else if (EnableBackgroundAutosave.Value)
{
GameSave_Patch.Enable(enable: true);
}
if (EnableFastLoading.Value)
{
try
{
harmony.PatchAll(typeof(GameLoader_Patch));
}
catch
{
Log.Warn("Fast loading patch didn't success!");
}
}
if (RemoveGC.Value)
{
try
{
harmony.PatchAll(typeof(BuildTool_Patch));
return;
}
catch
{
Log.Warn("BuildTool no GC patch didn't success!");
return;
}
}
}
catch (Exception ex)
{
((BaseUnityPlugin)this).Logger.LogError((object)ex);
throw ex;
}
}
public void Update()
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
if (Input.GetKeyDown(KeyPause.Value))
{
IngameUI.OnKeyPause();
}
KeyboardShortcut value = KeyAutosave.Value;
if (((KeyboardShortcut)(ref value)).IsDown() && UIRoot.instance.uiGame.autoSave.showTime == 0f)
{
UIAutoSave.lastSaveTick = 0L;
Log.Debug("Trigger auto save by hotkey");
}
}
public void OnDestroy()
{
harmony.UnpatchSelf();
harmony = null;
IngameUI.Dispose();
GameSave_Patch.Enable(enable: false);
if (Chainloader.PluginInfos.ContainsKey("dsp.nebula-multiplayer"))
{
NebulaCompat.Dispose();
}
}
}
public static class Log
{
private static ManualLogSource _logger;
private static int count;
public static void Init(ManualLogSource logger)
{
_logger = logger;
}
public static void Error(object obj)
{
_logger.LogError(obj);
}
public static void Warn(object obj)
{
_logger.LogWarning(obj);
}
public static void Info(object obj)
{
_logger.LogInfo(obj);
}
public static void Debug(object obj)
{
_logger.LogDebug(obj);
}
[Conditional("DEBUG")]
public static void Dev(object obj)
{
_logger.LogDebug(obj);
}
public static void Print(int period, object obj)
{
if (count++ % period == 0)
{
_logger.LogDebug(obj);
}
}
}