using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using DSP_CustomFastStart.CustomFastStart.Patchers;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
[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: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.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]
[Microsoft.CodeAnalysis.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]
[Microsoft.CodeAnalysis.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 DSP_CustomFastStart.CustomFastStart
{
[BepInPlugin("stat0s2p.dsp.custom-fast-start", "DSP Custom Fast Start", "0.1.2")]
public class CustomFastStartPlugin : BaseUnityPlugin
{
internal static readonly ManualLogSource Log = Logger.CreateLogSource("DSP Custom Fast Start");
internal static ConfigEntry<bool> EnableFastStart = null;
internal static ConfigEntry<bool> ClearPackageBeforeGrantItems = null;
internal static ConfigEntry<string> TechIdsCombat = null;
internal static ConfigEntry<string> TechIdsNonCombat = null;
internal static ConfigEntry<string> ItemsCombat = null;
internal static ConfigEntry<string> ItemsNonCombat = null;
private Harmony? _harmony;
internal void Awake()
{
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: Expected O, but got Unknown
EnableFastStart = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableFastStart", true, "Whether custom fast start is enabled.");
ClearPackageBeforeGrantItems = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ClearPackageBeforeGrantItems", true, "Whether to clear player package before adding configured items.");
TechIdsCombat = ((BaseUnityPlugin)this).Config.Bind<string>("Combat", "TechIds", string.Empty, "Tech list for combat mode. Format: techId1;techId2.");
TechIdsNonCombat = ((BaseUnityPlugin)this).Config.Bind<string>("NonCombat", "TechIds", string.Empty, "Tech list for non-combat mode. Format: techId1;techId2.");
ItemsCombat = ((BaseUnityPlugin)this).Config.Bind<string>("Combat", "Items", "2003:300;2318:50;2316:30;2319:50;2210:20;2902:20;2202:100;2201:100;2212:30;1210:100;1131:1000;2014:200;2020:50;1804:50;2307:20;2308:20;2317:30;2310:20;2103:10;2104:10;2105:10;3008:20;3007:20;3009:20;3002:50", "Item list for combat mode. Format: itemId(:count);itemId2(:count2).");
ItemsNonCombat = ((BaseUnityPlugin)this).Config.Bind<string>("NonCombat", "Items", "2003:300;2318:50;2316:30;2319:50;2210:20;2902:20;2202:100;2201:100;2212:30;1210:100;1131:1000;2014:200;2020:50;1804:50;2307:20;2308:20;2317:30;2310:20;2103:10;2104:10;2105:10", "Item list for non-combat mode. Format: itemId(:count);itemId2(:count2).");
_harmony = new Harmony("stat0s2p.dsp.custom-fast-start");
_harmony.PatchAll(typeof(GameStartPatcher));
Log.LogInfo((object)"Custom fast start initialized.");
}
internal void OnDestroy()
{
Harmony? harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
}
internal static class ModInfo
{
public const string ModGuid = "stat0s2p.dsp.custom-fast-start";
public const string ModName = "DSP Custom Fast Start";
public const string Version = "0.1.2";
}
}
namespace DSP_CustomFastStart.CustomFastStart.Patchers
{
public static class GameStartPatcher
{
private enum FastStartContext
{
Unknown,
NewGameRequested,
LoadedSave
}
private readonly struct ItemGrant
{
public int ItemId { get; }
public int Count { get; }
public ItemGrant(int itemId, int count)
{
ItemId = itemId;
Count = count;
}
}
private static bool _appliedForCurrentGame;
private static bool _galaxySelectOpened;
private static bool _startupStateLogged;
private static bool _pendingNewGameFlow;
private static FastStartContext _context;
[HarmonyPrefix]
[HarmonyPatch(typeof(GameSave), "LoadCurrentGame")]
public static void LoadCurrentGamePrefix()
{
if (_pendingNewGameFlow)
{
CustomFastStartPlugin.Log.LogInfo((object)"FastStart mark: LoadCurrentGame observed during pending new-game flow; keeping NewGameRequested context.");
return;
}
_context = FastStartContext.LoadedSave;
CustomFastStartPlugin.Log.LogInfo((object)"FastStart mark: session entered via LoadCurrentGame (treated as save load).");
}
[HarmonyPostfix]
[HarmonyPatch(typeof(UIGalaxySelect), "_OnOpen")]
public static void GalaxySelectOnOpenPostfix()
{
_galaxySelectOpened = true;
_pendingNewGameFlow = false;
_context = FastStartContext.Unknown;
CustomFastStartPlugin.Log.LogInfo((object)"FastStart mark: galaxy select opened (new game flow).");
}
[HarmonyPostfix]
[HarmonyPatch(typeof(UIGalaxySelect), "_OnClose")]
public static void GalaxySelectOnClosePostfix()
{
if (_galaxySelectOpened)
{
_context = FastStartContext.NewGameRequested;
_pendingNewGameFlow = true;
_galaxySelectOpened = false;
CustomFastStartPlugin.Log.LogInfo((object)"FastStart mark: galaxy select closed, new game requested.");
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(UIRoot), "OnGameBegin")]
public static void OnGameBeginPostfix()
{
_appliedForCurrentGame = false;
_startupStateLogged = false;
CustomFastStartPlugin.Log.LogInfo((object)"FastStart reset: OnGameBegin.");
}
[HarmonyPostfix]
[HarmonyPatch(typeof(GameLogic), "LogicFrame")]
public static void OnLogicFramePostfix()
{
if (_appliedForCurrentGame || !CustomFastStartPlugin.EnableFastStart.Value || (Object)(object)GameMain.instance == (Object)null || GameMain.data == null || GameMain.instance.timei < 2 || GameMain.data.mainPlayer == null)
{
return;
}
if (!_startupStateLogged)
{
_startupStateLogged = true;
CustomFastStartPlugin.Log.LogInfo((object)$"FastStart check: timei={GameMain.instance.timei}, context={_context}.");
}
if (_context != FastStartContext.NewGameRequested)
{
_appliedForCurrentGame = true;
_pendingNewGameFlow = false;
CustomFastStartPlugin.Log.LogInfo((object)$"Fast start skipped because context is {_context}, not NewGameRequested.");
return;
}
try
{
_appliedForCurrentGame = true;
_pendingNewGameFlow = false;
ApplyFastStart();
}
catch (Exception arg)
{
_appliedForCurrentGame = true;
_pendingNewGameFlow = false;
CustomFastStartPlugin.Log.LogError((object)$"Fast start apply failed: {arg}");
}
}
private static void ApplyFastStart()
{
bool isCombatMode = GameMain.data.gameDesc.isCombatMode;
string text = (isCombatMode ? CustomFastStartPlugin.TechIdsCombat.Value : CustomFastStartPlugin.TechIdsNonCombat.Value);
string text2 = (isCombatMode ? CustomFastStartPlugin.ItemsCombat.Value : CustomFastStartPlugin.ItemsNonCombat.Value);
bool flag = !string.IsNullOrWhiteSpace(text);
bool flag2 = !string.IsNullOrWhiteSpace(text2);
if (!flag && !flag2)
{
CustomFastStartPlugin.Log.LogInfo((object)"Fast start skipped: both tech and item configs are empty.");
return;
}
CustomFastStartPlugin.Log.LogInfo((object)$"Fast start apply begin. isCombat={isCombatMode}, hasTechConfig={flag}, hasItemConfig={flag2}.");
if (flag)
{
if (!TryUnlockTechs(text, out int unlockedCount, out string error))
{
CustomFastStartPlugin.Log.LogWarning((object)("Fast start tech config parse failed: " + error));
}
else
{
CustomFastStartPlugin.Log.LogInfo((object)$"Fast start unlocked techs: {unlockedCount}.");
}
}
if (!flag2)
{
return;
}
if (!TryParseItems(text2, out List<ItemGrant> items, out string error2))
{
CustomFastStartPlugin.Log.LogWarning((object)("Fast start item config parse failed: " + error2));
return;
}
if (CustomFastStartPlugin.ClearPackageBeforeGrantItems.Value)
{
ClearPackage();
}
int num = GrantItems(items);
CustomFastStartPlugin.Log.LogInfo((object)$"Fast start granted item stacks: {num}.");
}
private static bool TryUnlockTechs(string techConfig, out int unlockedCount, out string? error)
{
unlockedCount = 0;
error = null;
if (!TryParseTechIds(techConfig, out List<int> techIds, out error))
{
return false;
}
foreach (int item in techIds)
{
if (!GameMain.data.history.TechUnlocked(item))
{
GameMain.data.history.UnlockTechUnlimited(item, true);
unlockedCount++;
}
}
return true;
}
private static bool TryParseTechIds(string rawConfig, out List<int> techIds, out string? error)
{
techIds = new List<int>();
error = null;
string[] array = rawConfig.Split(new char[1] { ';' });
for (int i = 0; i < array.Length; i++)
{
string text = array[i].Trim();
if (text.Length != 0)
{
if (!int.TryParse(text, out var result))
{
error = "invalid tech id '" + text + "'";
return false;
}
if (((ProtoSet<TechProto>)(object)LDB.techs).Select(result) == null)
{
error = $"tech id not found '{result}'";
return false;
}
techIds.Add(result);
}
}
if (techIds.Count == 0)
{
error = "no valid tech ids";
return false;
}
return true;
}
private static bool TryParseItems(string rawConfig, out List<ItemGrant> items, out string? error)
{
items = new List<ItemGrant>();
error = null;
string[] array = rawConfig.Split(new char[1] { ';' });
for (int i = 0; i < array.Length; i++)
{
string text = array[i].Trim();
if (text.Length != 0)
{
string[] array2 = text.Split(new char[1] { ':' });
if (array2.Length == 0 || array2.Length > 2)
{
error = "invalid item segment '" + text + "'";
return false;
}
if (!int.TryParse(array2[0].Trim(), out var result))
{
error = "invalid item id '" + array2[0] + "'";
return false;
}
if (((ProtoSet<ItemProto>)(object)LDB.items).Select(result) == null)
{
error = $"item id not found '{result}'";
return false;
}
int result2 = 1;
if (array2.Length == 2 && !int.TryParse(array2[1].Trim(), out result2))
{
error = "invalid item count '" + array2[1] + "'";
return false;
}
if (result2 <= 0)
{
error = $"item count must be > 0 for item '{result}'";
return false;
}
items.Add(new ItemGrant(result, result2));
}
}
if (items.Count == 0)
{
error = "no valid items";
return false;
}
return true;
}
private static void ClearPackage()
{
GameData data = GameMain.data;
object obj;
if (data == null)
{
obj = null;
}
else
{
Player mainPlayer = data.mainPlayer;
obj = ((mainPlayer != null) ? mainPlayer.package : null);
}
if (obj == null)
{
return;
}
StorageComponent package = GameMain.data.mainPlayer.package;
ItemProto[] dataArray = ((ProtoSet<ItemProto>)(object)LDB.items).dataArray;
int num = default(int);
foreach (ItemProto val in dataArray)
{
if (val != null)
{
int iD = ((Proto)val).ID;
int itemCount = package.GetItemCount(iD);
if (itemCount > 0)
{
package.TakeTailItems(ref iD, ref itemCount, ref num, false);
}
}
}
}
private static int GrantItems(List<ItemGrant> items)
{
int num = 0;
foreach (ItemGrant item in items)
{
GameMain.data.mainPlayer.TryAddItemToPackage(item.ItemId, item.Count, 0, false, 0, false);
num++;
}
return num;
}
}
}