using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using IL;
using IL.GameNetcodeStuff;
using Microsoft.CodeAnalysis;
using Mono.Cecil.Cil;
using MonoMod.Cil;
using On;
using On.GameNetcodeStuff;
using SmartItemSaving.Fixes;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("SmartItemSaving")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("A mod for Lethal Company")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+462be6473b002a343c431db4f5928d445fdb6193")]
[assembly: AssemblyProduct("SmartItemSaving")]
[assembly: AssemblyTitle("SmartItemSaving")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace SmartItemSaving
{
public static class Compatibility
{
public static bool HasSaveItemRotations()
{
PluginInfo pluginInfo;
return HasSaveItemRotations(out pluginInfo);
}
public static bool HasSaveItemRotations(out PluginInfo pluginInfo)
{
return Chainloader.PluginInfos.TryGetValue("moe.sylvi.SaveItemRotations", out pluginInfo);
}
public static bool HasLethalLevelLoader()
{
PluginInfo pluginInfo;
return HasLethalLevelLoader(out pluginInfo);
}
public static bool HasLethalLevelLoader(out PluginInfo pluginInfo)
{
return Chainloader.PluginInfos.TryGetValue("imabatby.lethallevelloader", out pluginInfo);
}
}
public class Config
{
public static ConfigEntry<bool> FixItemIds { get; private set; }
public static ConfigEntry<bool> RemoveIfNotFound { get; private set; }
public static ConfigEntry<bool> SaveItemRotation { get; private set; }
public static ConfigEntry<bool> FixItemFalling { get; private set; }
public static ConfigEntry<bool> BetterSyncItems { get; private set; }
public static ConfigEntry<bool> BackupOnLoad { get; private set; }
public static ConfigEntry<bool> ForceHandleFixItemIds { get; private set; }
public static ConfigEntry<bool> ForceHandleSaveItemRotation { get; private set; }
public Config(ConfigFile cfg)
{
FixItemIds = cfg.Bind<bool>("FixItemIds", "Enabled", true, "Attempts to fix changed item ids on load by comparing the saved item names.");
RemoveIfNotFound = cfg.Bind<bool>("FixItemIds", "RemoveIfNotFound", true, "Removes items with missing names instead of replacing them with an item of the same ID.");
SaveItemRotation = cfg.Bind<bool>("Misc", "SaveItemRotation", true, "Saves and loads the rotation of items on the ship.");
FixItemFalling = cfg.Bind<bool>("Misc", "FixItemFalling", true, "Fixes items falling through furniture on load.");
BetterSyncItems = cfg.Bind<bool>("Misc", "BetterSyncItems", true, "[CLIENT AND HOST] Correctly synchronizes item positions and rotations upon joining (important for Fix Item Falling and Save Item Rotation).");
BackupOnLoad = cfg.Bind<bool>("Misc", "BackupOnLoad", true, "Whether save files should be backed up on load incase the mod causes any destructive behaviour. NOTE: Only one backup is made!");
ForceHandleFixItemIds = cfg.Bind<bool>("Compatibility", "ForceHandleFixItemIds", false, "Forces this mod to handle item ID fixing even if the mod LethalLevelLoader is active, which uses a generally more comprehensive ID fixing system.");
ForceHandleSaveItemRotation = cfg.Bind<bool>("Compatibility", "ForceHandleSaveItemRotation", false, "Forces this mod to handle item rotation loading even if the mod SaveItemRotations is active.");
}
}
public class Patches
{
[CompilerGenerated]
private static class <>O
{
public static Manipulator <0>__GameNetworkManager_SaveGameValues;
public static Manipulator <1>__GameNetworkManager_SaveItemsInShip;
public static hook_SetTimeAndPlanetToSavedSettings <2>__StartOfRound_SetTimeAndPlanetToSavedSettings;
public static Manipulator <3>__StartOfRound_LoadUnlockables;
public static Manipulator <4>__StartOfRound_LoadShipGrabbableItems;
public static hook_Start <5>__GrabbableObject_Start;
public static hook_Update <6>__GrabbableObject_Update;
public static hook_ConnectClientToPlayerObject <7>__PlayerControllerB_ConnectClientToPlayerObject;
public static Manipulator <8>__PlayerControllerB_ThrowObjectClientRpc;
public static Action<GameNetworkManager> <9>__SaveInitialValues;
public static Action<GameNetworkManager, List<int>> <10>__SaveFixUnlockIds;
public static Action<GameNetworkManager> <11>__DeleteItemKeys;
public static Action <12>__PreSave;
public static Action<GrabbableObject[], int> <13>__Save;
public static Func<Vector3, GrabbableObject[], int, Vector3> <14>__Save;
}
public static void Initialize()
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected O, but got Unknown
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Expected O, but got Unknown
//IL_0053: 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_005e: Expected O, but got Unknown
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Expected O, but got Unknown
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
//IL_00a0: Expected O, but got Unknown
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
//IL_00c1: Expected O, but got Unknown
//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
//IL_00e2: Expected O, but got Unknown
//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0103: Expected O, but got Unknown
//IL_0119: 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_0124: Expected O, but got Unknown
object obj = <>O.<0>__GameNetworkManager_SaveGameValues;
if (obj == null)
{
Manipulator val = GameNetworkManager_SaveGameValues;
<>O.<0>__GameNetworkManager_SaveGameValues = val;
obj = (object)val;
}
GameNetworkManager.SaveGameValues += (Manipulator)obj;
object obj2 = <>O.<1>__GameNetworkManager_SaveItemsInShip;
if (obj2 == null)
{
Manipulator val2 = GameNetworkManager_SaveItemsInShip;
<>O.<1>__GameNetworkManager_SaveItemsInShip = val2;
obj2 = (object)val2;
}
GameNetworkManager.SaveItemsInShip += (Manipulator)obj2;
object obj3 = <>O.<2>__StartOfRound_SetTimeAndPlanetToSavedSettings;
if (obj3 == null)
{
hook_SetTimeAndPlanetToSavedSettings val3 = StartOfRound_SetTimeAndPlanetToSavedSettings;
<>O.<2>__StartOfRound_SetTimeAndPlanetToSavedSettings = val3;
obj3 = (object)val3;
}
StartOfRound.SetTimeAndPlanetToSavedSettings += (hook_SetTimeAndPlanetToSavedSettings)obj3;
object obj4 = <>O.<3>__StartOfRound_LoadUnlockables;
if (obj4 == null)
{
Manipulator val4 = StartOfRound_LoadUnlockables;
<>O.<3>__StartOfRound_LoadUnlockables = val4;
obj4 = (object)val4;
}
StartOfRound.LoadUnlockables += (Manipulator)obj4;
object obj5 = <>O.<4>__StartOfRound_LoadShipGrabbableItems;
if (obj5 == null)
{
Manipulator val5 = StartOfRound_LoadShipGrabbableItems;
<>O.<4>__StartOfRound_LoadShipGrabbableItems = val5;
obj5 = (object)val5;
}
StartOfRound.LoadShipGrabbableItems += (Manipulator)obj5;
object obj6 = <>O.<5>__GrabbableObject_Start;
if (obj6 == null)
{
hook_Start val6 = GrabbableObject_Start;
<>O.<5>__GrabbableObject_Start = val6;
obj6 = (object)val6;
}
GrabbableObject.Start += (hook_Start)obj6;
object obj7 = <>O.<6>__GrabbableObject_Update;
if (obj7 == null)
{
hook_Update val7 = GrabbableObject_Update;
<>O.<6>__GrabbableObject_Update = val7;
obj7 = (object)val7;
}
GrabbableObject.Update += (hook_Update)obj7;
object obj8 = <>O.<7>__PlayerControllerB_ConnectClientToPlayerObject;
if (obj8 == null)
{
hook_ConnectClientToPlayerObject val8 = PlayerControllerB_ConnectClientToPlayerObject;
<>O.<7>__PlayerControllerB_ConnectClientToPlayerObject = val8;
obj8 = (object)val8;
}
PlayerControllerB.ConnectClientToPlayerObject += (hook_ConnectClientToPlayerObject)obj8;
object obj9 = <>O.<8>__PlayerControllerB_ThrowObjectClientRpc;
if (obj9 == null)
{
Manipulator val9 = PlayerControllerB_ThrowObjectClientRpc;
<>O.<8>__PlayerControllerB_ThrowObjectClientRpc = val9;
obj9 = (object)val9;
}
PlayerControllerB.ThrowObjectClientRpc += (Manipulator)obj9;
}
private static void GameNetworkManager_SaveGameValues(ILContext il)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Expected O, but got Unknown
//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
ILCursor val = new ILCursor(il);
int unlockListLoc = -1;
if (!val.TryGotoNext((MoveType)0, new Func<Instruction, bool>[2]
{
(Instruction instr1) => ILPatternMatchingExt.MatchLdstr(instr1, "UnlockedShipObjects"),
(Instruction instr2) => ILPatternMatchingExt.MatchLdloc(instr2, ref unlockListLoc)
}))
{
Plugin.Logger.LogError((object)"Failed IL hook for GameNetworkManager.SaveGameValues @ Save unlocked ship objects list");
return;
}
Instruction next = val.Next;
if (!val.TryGotoPrev((MoveType)2, new Func<Instruction, bool>[1]
{
(Instruction instr) => ILPatternMatchingExt.MatchStloc(instr, unlockListLoc)
}))
{
Plugin.Logger.LogError((object)"Failed IL hook for GameNetworkManager.SaveGameValues @ After initialize unlocks list");
return;
}
val.MoveAfterLabels();
val.Emit(OpCodes.Ldarg_0);
val.EmitDelegate<Action<GameNetworkManager>>((Action<GameNetworkManager>)General.SaveInitialValues);
val.Goto(next, (MoveType)1, false);
val.Emit(OpCodes.Ldarg_0);
val.Emit(OpCodes.Ldloc, unlockListLoc);
val.EmitDelegate<Action<GameNetworkManager, List<int>>>((Action<GameNetworkManager, List<int>>)FixUnlockIds.SaveFixUnlockIds);
}
private static void GameNetworkManager_SaveItemsInShip(ILContext il)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Expected O, but got Unknown
//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
//IL_0298: Unknown result type (might be due to invalid IL or missing references)
//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
//IL_032c: Unknown result type (might be due to invalid IL or missing references)
//IL_033e: Unknown result type (might be due to invalid IL or missing references)
//IL_03bd: Unknown result type (might be due to invalid IL or missing references)
//IL_03c9: Unknown result type (might be due to invalid IL or missing references)
ILCursor val = new ILCursor(il);
if (!val.TryGotoNext((MoveType)0, new Func<Instruction, bool>[1]
{
(Instruction instr) => ILPatternMatchingExt.MatchCallOrCallvirt<Object>(instr, "FindObjectsByType")
}))
{
Plugin.Logger.LogError((object)"Failed IL hook for GameNetworkManager.SaveItemsInShip @ Find grabbable objects");
return;
}
int grabbableObjectsLoc = -1;
if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
{
(Instruction instr) => ILPatternMatchingExt.MatchStloc(instr, ref grabbableObjectsLoc)
}))
{
Plugin.Logger.LogError((object)"Failed IL hook for GameNetworkManager.SaveItemsInShip @ Get grabbable objects local");
return;
}
if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
{
(Instruction instr) => ILPatternMatchingExt.MatchCallOrCallvirt<ES3>(instr, "DeleteKey")
}))
{
Plugin.Logger.LogError((object)"Failed IL hook for GameNetworkManager.SaveItemsInShip @ Delete empty keys");
return;
}
val.Emit(OpCodes.Ldarg_0);
val.EmitDelegate<Action<GameNetworkManager>>((Action<GameNetworkManager>)General.DeleteItemKeys);
int[] array = new int[4];
for (int i = 0; i < array.Length; i++)
{
int loc = -1;
if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
{
(Instruction instr) => ILPatternMatchingExt.MatchStloc(instr, ref loc)
}))
{
Plugin.Logger.LogError((object)$"Failed IL hook for GameNetworkManager.SaveItemsInShip @ Get list {i} local");
return;
}
array[i] = loc;
}
int num = array[0];
int posLoc = array[1];
int num2 = array[2];
int num3 = array[3];
int iLoc = -1;
ILLabel val2 = default(ILLabel);
if (!val.TryGotoNext((MoveType)0, new Func<Instruction, bool>[3]
{
(Instruction instr1) => ILPatternMatchingExt.MatchLdcI4(instr1, 0),
(Instruction instr2) => ILPatternMatchingExt.MatchStloc(instr2, ref iLoc),
(Instruction instr3) => ILPatternMatchingExt.MatchBr(instr3, ref val2)
}))
{
Plugin.Logger.LogError((object)"Failed IL hook for GameNetworkManager.SaveItemsInShip @ Get loop 'i' local");
return;
}
val.EmitDelegate<Action>((Action)FixItemRotation.PreSave);
if (!val.TryGotoNext((MoveType)0, new Func<Instruction, bool>[1]
{
(Instruction instr) => ILPatternMatchingExt.MatchLdloc(instr, posLoc)
}))
{
Plugin.Logger.LogError((object)"Failed IL hook for GameNetworkManager.SaveItemsInShip @ Before add item position");
return;
}
val.Emit(OpCodes.Ldloc, grabbableObjectsLoc);
val.Emit(OpCodes.Ldloc, iLoc);
val.EmitDelegate<Action<GrabbableObject[], int>>((Action<GrabbableObject[], int>)FixItemRotation.Save);
if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
{
(Instruction instr) => ILPatternMatchingExt.MatchCallOrCallvirt<Transform>(instr, "get_position")
}))
{
Plugin.Logger.LogError((object)"Failed IL hook for GameNetworkManager.SaveItemsInShip @ Get item position");
return;
}
val.Emit(OpCodes.Ldloc, grabbableObjectsLoc);
val.Emit(OpCodes.Ldloc, iLoc);
val.EmitDelegate<Func<Vector3, GrabbableObject[], int, Vector3>>((Func<Vector3, GrabbableObject[], int, Vector3>)FixItemFalling.Save);
if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
{
(Instruction instr) => ILPatternMatchingExt.MatchCallOrCallvirt<ES3>(instr, "Save")
}))
{
Plugin.Logger.LogError((object)"Failed IL hook for GameNetworkManager.SaveItemsInShip @ First save call");
return;
}
val.Emit(OpCodes.Ldarg_0);
val.Emit(OpCodes.Ldloc, num);
val.EmitDelegate<Action<GameNetworkManager, List<int>>>((Action<GameNetworkManager, List<int>>)delegate(GameNetworkManager self, List<int> ids)
{
FixItemRotation.PostSave(self);
FixItemIds.Save(self, ids);
});
}
private static void StartOfRound_SetTimeAndPlanetToSavedSettings(orig_SetTimeAndPlanetToSavedSettings orig, StartOfRound self)
{
General.LoadCreateBackup();
orig.Invoke(self);
General.LoadInitialValues(self);
}
private static void StartOfRound_LoadUnlockables(ILContext il)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Expected O, but got Unknown
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
ILCursor val = new ILCursor(il);
if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
{
(Instruction instr) => ILPatternMatchingExt.MatchCallOrCallvirt<ES3>(instr, "Load")
}))
{
Plugin.Logger.LogError((object)"Failed IL hook for StartOfRound.LoadUnlockables @ Load unlocks list");
return;
}
val.Emit(OpCodes.Ldarg_0);
val.EmitDelegate<Func<int[], StartOfRound, int[]>>((Func<int[], StartOfRound, int[]>)delegate(int[] unlocks, StartOfRound self)
{
try
{
FixUnlockIds.LoadFixUnlockIds(self, ref unlocks);
}
catch (Exception ex)
{
Plugin.Logger.LogError((object)"Load | Unlocks | Error occured during load");
Plugin.Logger.LogError((object)ex);
}
return unlocks;
});
}
private static void StartOfRound_LoadShipGrabbableItems(ILContext il)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Expected O, but got Unknown
//IL_019e: Unknown result type (might be due to invalid IL or missing references)
//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
//IL_01ce: 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_0238: Unknown result type (might be due to invalid IL or missing references)
//IL_0270: Unknown result type (might be due to invalid IL or missing references)
//IL_0395: Unknown result type (might be due to invalid IL or missing references)
//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
ILCursor val = new ILCursor(il);
int idsLoc = -1;
if (!val.TryGotoNext((MoveType)0, new Func<Instruction, bool>[1]
{
(Instruction instr) => ILPatternMatchingExt.MatchLdstr(instr, "shipGrabbableItemIDs")
}) || !val.TryGotoNext((MoveType)1, new Func<Instruction, bool>[1]
{
(Instruction instr) => ILPatternMatchingExt.MatchStloc(instr, ref idsLoc)
}))
{
Plugin.Logger.LogError((object)"Failed IL hook for StartOfRound.LoadShipGrabbableItems @ Get item IDs local");
return;
}
ILLabel val3 = default(ILLabel);
if (!val.TryGotoNext((MoveType)0, new Func<Instruction, bool>[2]
{
(Instruction instr1) => ILPatternMatchingExt.MatchBrfalse(instr1, ref val3),
(Instruction instr2) => ILPatternMatchingExt.MatchLdstr(instr2, "shipScrapValues")
}))
{
Plugin.Logger.LogError((object)"Failed IL hook for StartOfRound.LoadShipGrabbableItems @ Load values");
return;
}
int valuesLoc = -1;
if (!val.TryGotoNext((MoveType)0, new Func<Instruction, bool>[1]
{
(Instruction instr) => ILPatternMatchingExt.MatchStloc(instr, ref valuesLoc)
}))
{
Plugin.Logger.LogError((object)"Failed IL hook for StartOfRound.LoadShipGrabbableItems @ Get item values local");
return;
}
int dataLoc = 1;
if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[2]
{
(Instruction instr1) => ILPatternMatchingExt.MatchCallOrCallvirt<ES3>(instr1, "Load"),
(Instruction instr2) => ILPatternMatchingExt.MatchStloc(instr2, ref dataLoc)
}))
{
Plugin.Logger.LogError((object)"Failed IL hook for StartOfRound.LoadShipGrabbableItems @ Get item data local");
return;
}
val.MoveAfterLabels();
val.Emit(OpCodes.Ldarg_0);
val.Emit(OpCodes.Ldloc, idsLoc);
val.Emit(OpCodes.Ldloc, valuesLoc);
val.Emit(OpCodes.Ldloc, dataLoc);
val.EmitDelegate<Func<StartOfRound, int[], int[], int[], (int[], int[])>>((Func<StartOfRound, int[], int[], int[], (int[], int[])>)delegate(StartOfRound self, int[] ids, int[] values, int[] data)
{
try
{
FixItemFalling.PreLoad();
FixItemRotation.PreLoad(ids);
FixItemIds.Load(self, ids, ref values, ref data);
}
catch (Exception ex2)
{
Plugin.Logger.LogError((object)"Load | Items | Error occured during pre-load");
Plugin.Logger.LogError((object)ex2);
}
return (values, data);
});
val.Emit(OpCodes.Dup);
val.EmitDelegate<Func<(int[], int[]), int[]>>((Func<(int[], int[]), int[]>)(((int[], int[]) tuple) => tuple.Item1));
val.Emit(OpCodes.Stloc, valuesLoc);
val.EmitDelegate<Func<(int[], int[]), int[]>>((Func<(int[], int[]), int[]>)(((int[], int[]) tuple) => tuple.Item2));
val.Emit(OpCodes.Stloc, dataLoc);
int iLoc = -1;
ILLabel val2 = default(ILLabel);
if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[3]
{
(Instruction instr1) => ILPatternMatchingExt.MatchLdcI4(instr1, 0),
(Instruction instr2) => ILPatternMatchingExt.MatchStloc(instr2, ref iLoc),
(Instruction instr3) => ILPatternMatchingExt.MatchBr(instr3, ref val2)
}))
{
Plugin.Logger.LogError((object)"Failed IL hook for StartOfRound.LoadShipGrabbableItems @ Get loop 'i' local");
return;
}
if (!val.TryGotoNext((MoveType)0, new Func<Instruction, bool>[1]
{
(Instruction instr) => ILPatternMatchingExt.MatchCallOrCallvirt<GameObject>(instr, "GetComponent")
}))
{
Plugin.Logger.LogError((object)"Failed IL hook for StartOfRound.LoadShipGrabbableItems @ Grabbable object instantiation");
return;
}
int grabbableObjectLoc = -1;
if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
{
(Instruction instr) => ILPatternMatchingExt.MatchStloc(instr, ref grabbableObjectLoc)
}))
{
Plugin.Logger.LogError((object)"Failed IL hook for StartOfRound.LoadShipGrabbableItems @ Get grabbable object local");
return;
}
val.Emit(OpCodes.Ldloc, iLoc);
val.Emit(OpCodes.Ldloc, grabbableObjectLoc);
val.EmitDelegate<Action<int, GrabbableObject>>((Action<int, GrabbableObject>)delegate(int i, GrabbableObject grabbableObject)
{
try
{
FixItemFalling.Load(grabbableObject);
FixItemRotation.Load(i, grabbableObject);
}
catch (Exception ex)
{
Plugin.Logger.LogError((object)"Load | Items | Error occured during load");
Plugin.Logger.LogError((object)ex);
}
});
}
private static void GrabbableObject_Update(orig_Update orig, GrabbableObject self)
{
orig.Invoke(self);
FixItemRotation.Apply(self);
}
private static void GrabbableObject_Start(orig_Start orig, GrabbableObject self)
{
orig.Invoke(self);
FixItemFalling.Apply(self);
}
private static void PlayerControllerB_ConnectClientToPlayerObject(orig_ConnectClientToPlayerObject orig, PlayerControllerB self)
{
orig.Invoke(self);
BetterSyncItems.InitializeNetworkingAndSync();
}
private static void PlayerControllerB_ThrowObjectClientRpc(ILContext il)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Expected O, but got Unknown
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
ILCursor val = new ILCursor(il);
if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
{
(Instruction instr) => ILPatternMatchingExt.MatchLdcI4(instr, -1)
}))
{
Plugin.Logger.LogWarning((object)"Failed IL hook for PlayerControllerB.ThrowObjectClientRpc @ Pass -1 (Not a big deal)");
return;
}
val.Emit(OpCodes.Ldarg, 5);
val.EmitDelegate<Func<int, int, int>>((Func<int, int, int>)((int orig, int floorYRot) => (!Config.BetterSyncItems.Value) ? orig : floorYRot));
}
}
[BepInPlugin("SylviBlossom.SmartItemSaving", "SmartItemSaving", "1.2.4")]
public class Plugin : BaseUnityPlugin
{
public const int FormatVersion = 2;
public static Plugin Instance { get; private set; }
public static Config Config { get; private set; }
public static ManualLogSource Logger { get; private set; }
private void Awake()
{
Instance = this;
Config = new Config(((BaseUnityPlugin)this).Config);
Logger = ((BaseUnityPlugin)this).Logger;
Patches.Initialize();
Logger.LogInfo((object)"Plugin SmartItemSaving is loaded!");
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "SylviBlossom.SmartItemSaving";
public const string PLUGIN_NAME = "SmartItemSaving";
public const string PLUGIN_VERSION = "1.2.4";
}
public static class SaveKeys
{
public const string FormatVersion = "SylviBlossom.SmartItemSaving_formatVersion";
public const string ParityStepsTaken = "SylviBlossom.SmartItemSaving_parityStepsTaken";
public const string ItemNames = "SylviBlossom.SmartItemSaving_itemNames";
public const string ItemHasValue = "SylviBlossom.SmartItemSaving_itemHasValue";
public const string ItemHasData = "SylviBlossom.SmartItemSaving_itemHasData";
public const string ItemRotations = "SylviBlossom.SmartItemSaving_itemRotations";
public const string UnlockNames = "SylviBlossom.SmartItemSaving_unlockNames";
}
}
namespace SmartItemSaving.Fixes
{
public static class BetterSyncItems
{
[CompilerGenerated]
private static class <>O
{
public static Func<GrabbableObject, bool> <0>__IsValidObject;
public static HandleNamedMessageDelegate <1>__OnRequestSync;
public static HandleNamedMessageDelegate <2>__OnReceiveSync;
}
internal static void RequestSync()
{
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
if (!NetworkManager.Singleton.IsClient)
{
return;
}
FastBufferWriter val = default(FastBufferWriter);
((FastBufferWriter)(ref val))..ctor(4, (Allocator)2, -1);
try
{
NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("SylviBlossom.SmartItemSaving_OnRequestItemSync", 0uL, val, (NetworkDelivery)3);
}
finally
{
((IDisposable)(FastBufferWriter)(ref val)).Dispose();
}
}
internal static void OnRequestSync(ulong clientId, FastBufferReader _)
{
if (NetworkManager.Singleton.IsHost)
{
SendSyncTo(clientId);
}
}
internal static void SendSyncTo(ulong clientId)
{
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
//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_00c7: 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_012b: Unknown result type (might be due to invalid IL or missing references)
if (!NetworkManager.Singleton.IsHost)
{
return;
}
GrabbableObject[] array = Object.FindObjectsOfType<GrabbableObject>().Where(IsValidObject).ToArray();
int num = Math.Min(array.Length, 999);
FastBufferWriter val = default(FastBufferWriter);
((FastBufferWriter)(ref val))..ctor(8 + 32 * num, (Allocator)2, 65536);
try
{
((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
for (int i = 0; i < num; i++)
{
NetworkObjectReference val2 = NetworkObjectReference.op_Implicit(((NetworkBehaviour)array[i]).NetworkObject);
((FastBufferWriter)(ref val)).WriteValueSafe<NetworkObjectReference>(ref val2, default(ForNetworkSerializable));
Vector3 position = ((Component)array[i]).transform.position;
((FastBufferWriter)(ref val)).WriteValueSafe(ref position);
position = ((Component)array[i]).transform.eulerAngles;
((FastBufferWriter)(ref val)).WriteValueSafe(ref position);
}
Plugin.Logger.LogInfo((object)$"Item rotation sync: Sending packet\n- Buffer size: {((FastBufferWriter)(ref val)).Capacity}\n- Bytes written: {((FastBufferWriter)(ref val)).Length}\n- Objects synced: {num}");
NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("SylviBlossom.SmartItemSaving_OnReceiveItemSync", clientId, val, (NetworkDelivery)4);
}
catch (Exception arg)
{
Plugin.Logger.LogError((object)$"Error occured syncing item rotations with client: {clientId}\n{arg}");
}
finally
{
((IDisposable)(FastBufferWriter)(ref val)).Dispose();
}
}
internal static void OnReceiveSync(ulong _, FastBufferReader reader)
{
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0071: 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_00f5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
try
{
if (!((FastBufferReader)(ref reader)).TryBeginRead(4))
{
Plugin.Logger.LogError((object)"Item rotation sync error: Could not begin reading buffer");
return;
}
int num = default(int);
((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
if (!((FastBufferReader)(ref reader)).TryBeginRead(32 * num))
{
Plugin.Logger.LogError((object)"Item rotation sync error: Invalid buffer size");
return;
}
NetworkObjectReference val = default(NetworkObjectReference);
Vector3 position = default(Vector3);
Vector3 eulerAngles = default(Vector3);
NetworkObject val2 = default(NetworkObject);
for (int i = 0; i < num; i++)
{
((FastBufferReader)(ref reader)).ReadValueSafe<NetworkObjectReference>(ref val, default(ForNetworkSerializable));
((FastBufferReader)(ref reader)).ReadValueSafe(ref position);
((FastBufferReader)(ref reader)).ReadValueSafe(ref eulerAngles);
if (!((NetworkObjectReference)(ref val)).TryGet(ref val2, (NetworkManager)null))
{
Plugin.Logger.LogWarning((object)$"Item rotation sync: Unknown object reference {((NetworkObjectReference)(ref val)).NetworkObjectId}");
continue;
}
GrabbableObject component = ((Component)val2).gameObject.GetComponent<GrabbableObject>();
if ((Object)(object)component != (Object)null && IsValidObject(component))
{
ApplyPositionTo(component, position);
ApplyRotationTo(component, eulerAngles);
}
}
}
catch (Exception arg)
{
Plugin.Logger.LogError((object)$"Error occured receiving item rotation sync!\n{arg}");
}
}
public static void InitializeNetworkingAndSync()
{
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Expected O, but got Unknown
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Expected O, but got Unknown
if (!Config.BetterSyncItems.Value)
{
return;
}
if (NetworkManager.Singleton.IsHost)
{
CustomMessagingManager customMessagingManager = NetworkManager.Singleton.CustomMessagingManager;
object obj = <>O.<1>__OnRequestSync;
if (obj == null)
{
HandleNamedMessageDelegate val = OnRequestSync;
<>O.<1>__OnRequestSync = val;
obj = (object)val;
}
customMessagingManager.RegisterNamedMessageHandler("SylviBlossom.SmartItemSaving_OnRequestItemSync", (HandleNamedMessageDelegate)obj);
return;
}
CustomMessagingManager customMessagingManager2 = NetworkManager.Singleton.CustomMessagingManager;
object obj2 = <>O.<2>__OnReceiveSync;
if (obj2 == null)
{
HandleNamedMessageDelegate val2 = OnReceiveSync;
<>O.<2>__OnReceiveSync = val2;
obj2 = (object)val2;
}
customMessagingManager2.RegisterNamedMessageHandler("SylviBlossom.SmartItemSaving_OnReceiveItemSync", (HandleNamedMessageDelegate)obj2);
RequestSync();
}
private static bool IsValidObject(GrabbableObject grabbableObject)
{
return !grabbableObject.isHeld && (Object)(object)grabbableObject.parentObject == (Object)null && grabbableObject.reachedFloorTarget;
}
private static void ApplyPositionTo(GrabbableObject grabbableObject, Vector3 position)
{
//IL_0019: 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)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
grabbableObject.fallTime = 1f;
grabbableObject.hasHitGround = true;
((Component)grabbableObject).transform.position = position;
grabbableObject.targetFloorPosition = ((Component)grabbableObject).transform.localPosition;
}
private static void ApplyRotationTo(GrabbableObject grabbableObject, Vector3 eulerAngles)
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
grabbableObject.floorYRot = -1;
((Component)grabbableObject).transform.rotation = Quaternion.Euler(((Component)grabbableObject).transform.eulerAngles.x, eulerAngles.y, ((Component)grabbableObject).transform.eulerAngles.z);
}
}
public static class FixItemFalling
{
public static HashSet<GrabbableObject> NeedsFixItemFalling = new HashSet<GrabbableObject>();
public static Vector3 Save(Vector3 position, GrabbableObject[] grabbableObjects, int i)
{
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: 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)
//IL_007d: 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_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
GrabbableObject val = grabbableObjects[i];
if (val.isHeld || (Object)(object)val.parentObject != (Object)null)
{
return val.GetItemFloorPosition(default(Vector3));
}
if (!val.reachedFloorTarget)
{
Vector3 val2 = val.targetFloorPosition;
if ((Object)(object)((Component)val).transform.parent != (Object)null)
{
val2 = ((Component)val).transform.parent.TransformPoint(val2);
}
return val2;
}
return position;
}
public static void PreLoad()
{
NeedsFixItemFalling = new HashSet<GrabbableObject>();
}
public static void Load(GrabbableObject grabbableObject)
{
if (Config.FixItemFalling.Value)
{
NeedsFixItemFalling.Add(grabbableObject);
}
}
public static void Apply(GrabbableObject grabbableObject)
{
//IL_0053: 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)
if (((NetworkBehaviour)StartOfRound.Instance).IsServer && NeedsFixItemFalling.Contains(grabbableObject) && grabbableObject.itemProperties.itemSpawnsOnGround)
{
grabbableObject.fallTime = 1f;
grabbableObject.hasHitGround = true;
grabbableObject.targetFloorPosition = ((Component)grabbableObject).transform.localPosition;
}
}
}
public static class FixItemIds
{
public static void Save(GameNetworkManager gameNetworkManager, List<int> ids)
{
string[] array = new string[ids.Count];
bool[] array2 = new bool[ids.Count];
bool[] array3 = new bool[ids.Count];
for (int i = 0; i < ids.Count; i++)
{
int num = ids[i];
List<Item> itemsList = StartOfRound.Instance.allItemsList.itemsList;
if (itemsList.Count < num || string.IsNullOrEmpty(itemsList[num].itemName))
{
Plugin.Logger.LogWarning((object)$"Save | Items | No item name found for item id {num}");
array[i] = "";
array2[i] = false;
array3[i] = false;
continue;
}
Item val = itemsList[num];
string name = val.itemName;
List<Item> list = itemsList.Where((Item x) => x.itemName.Equals(name, StringComparison.InvariantCultureIgnoreCase)).ToList();
int num2 = list.IndexOf(itemsList[num]);
if (list.Count > 1 && num2 >= 0)
{
name += $"##ID{num2}";
}
array[i] = name;
array2[i] = val.isScrap;
array3[i] = val.saveItemVariable;
}
ES3.Save<string[]>("SylviBlossom.SmartItemSaving_itemNames", array, gameNetworkManager.currentSaveFileName);
ES3.Save<bool[]>("SylviBlossom.SmartItemSaving_itemHasValue", array2, gameNetworkManager.currentSaveFileName);
ES3.Save<bool[]>("SylviBlossom.SmartItemSaving_itemHasData", array3, gameNetworkManager.currentSaveFileName);
Plugin.Logger.LogInfo((object)$"Save | Items | Successfully saved {array.Length} items");
}
public static void Load(StartOfRound startOfRound, int[] ids, ref int[] values, ref int[] data)
{
string currentSaveFileName = GameNetworkManager.Instance.currentSaveFileName;
if (!General.LoadedParityCheck)
{
return;
}
if (!ES3.KeyExists("SylviBlossom.SmartItemSaving_itemNames", currentSaveFileName))
{
Plugin.Logger.LogWarning((object)"Load | Items | No item name save data found, skipping item id fixing");
return;
}
string[] array = ES3.Load<string[]>("SylviBlossom.SmartItemSaving_itemNames", currentSaveFileName, new string[0]);
bool[] array2 = ES3.Load<bool[]>("SylviBlossom.SmartItemSaving_itemHasValue", currentSaveFileName, new bool[ids.Length]);
bool[] array3 = ES3.Load<bool[]>("SylviBlossom.SmartItemSaving_itemHasData", currentSaveFileName, new bool[ids.Length]);
if (!Config.FixItemIds.Value)
{
Plugin.Logger.LogInfo((object)"Load | Items | FixItemIds is disabled, skipping item id fixing");
return;
}
if (Compatibility.HasLethalLevelLoader(out var pluginInfo) && !Config.ForceHandleFixItemIds.Value)
{
Plugin.Logger.LogInfo((object)$"Load | Items | Found mod {pluginInfo.Metadata.Name} v{pluginInfo.Metadata.Version}, skipping item id fixing");
return;
}
if (array.Length != ids.Length)
{
Plugin.Logger.LogError((object)$"Load | Items | Item count mismatch (Expected {array.Length}, got {ids.Length}), likely outdated save, skipping item id fixing");
return;
}
int num = 0;
if (values != null)
{
for (int i = 0; i < values.Length; i++)
{
num += values[i];
}
}
for (int j = 0; j < ids.Length; j++)
{
int num2 = ids[j];
string text = array[j];
if (string.IsNullOrEmpty(text))
{
Plugin.Logger.LogWarning((object)$"Load | Items | Found empty item name for item id {num2}, loading normally");
continue;
}
string text2 = "";
if (startOfRound.allItemsList.itemsList.Count > num2 && !string.IsNullOrEmpty(startOfRound.allItemsList.itemsList[num2].itemName))
{
text2 = "as \"" + startOfRound.allItemsList.itemsList[num2].itemName + "\"";
}
int result = 0;
bool flag = false;
int num3 = text.IndexOf("##ID");
if (num3 != -1)
{
if (!int.TryParse(text.Substring(num3 + 4), out result))
{
Plugin.Logger.LogError((object)("Load | Items | Failed to parse item name " + text));
}
text = text.Substring(0, num3);
flag = true;
}
List<int> list = new List<int>();
for (int k = 0; k < startOfRound.allItemsList.itemsList.Count; k++)
{
Item val = startOfRound.allItemsList.itemsList[k];
if (val.itemName.Equals(text, StringComparison.InvariantCultureIgnoreCase))
{
list.Add(k);
}
}
if (list.Count == 0)
{
if (Config.RemoveIfNotFound.Value)
{
Plugin.Logger.LogWarning((object)("Load | Items | No item id found for item \"" + text + "\", removing item"));
ids[j] = int.MaxValue;
}
else
{
Plugin.Logger.LogWarning((object)$"Load | Items | No item id found for item \"{text}\", loading normally with id {num2} {text2}");
}
continue;
}
if (list.Count <= result)
{
Plugin.Logger.LogWarning((object)$"Load | Items | Saved {num2} as \"{text}\" #{result + 1}, but only found {list.Count} name duplicates, loading as #{list.Count}");
result = list.Count - 1;
}
if (list.Count > 1 && !flag)
{
string text3 = string.Join(",", list);
if (list.Contains(num2))
{
Plugin.Logger.LogWarning((object)$"Load | Items | Multiple ids ({text3}) found for item \"{text}\", loading normally with id {num2} {text2}");
continue;
}
Plugin.Logger.LogWarning((object)$"Load | Items | Multiple ids ({text3}) found for item \"{text}\", arbitrarily loading {list[0]}");
}
if (num2 != list[result])
{
if (num2 < startOfRound.allItemsList.itemsList.Count && num2 >= 0)
{
Plugin.Logger.LogInfo((object)$"Load | Items | Fixed item mismatch ({num2}, \"{startOfRound.allItemsList.itemsList[num2].itemName}\" -> {list[result]}, \"{text}\")");
}
else
{
Plugin.Logger.LogInfo((object)$"Load | Items | Fixed item mismatch ({num2}, unknown -> {list[result]}, \"{text}\")");
}
ids[j] = list[result];
}
}
List<int> list2 = new List<int>();
List<int> list3 = new List<int>();
int num4 = 0;
int num5 = 0;
int num6 = 0;
for (int l = 0; l < ids.Length; l++)
{
if (ids[l] < startOfRound.allItemsList.itemsList.Count)
{
Item val2 = startOfRound.allItemsList.itemsList[ids[l]];
if (val2.isScrap)
{
if (array2[l])
{
list2.Add(values[num4]);
num6 += values[num4];
}
else
{
int num7 = (int)((float)Random.Range(val2.minValue, val2.maxValue - 1) * RoundManager.Instance.scrapValueMultiplier);
list2.Add(num7);
num6 += num7;
Plugin.Logger.LogWarning((object)$"Load | Items | Assigning random value of {num7} to \"{val2.itemName}\"");
}
}
if (val2.saveItemVariable)
{
if (array3[l])
{
list3.Add(data[num5]);
}
else
{
list3.Add(0);
Plugin.Logger.LogWarning((object)("Load | Items | Loaded item \"" + val2.itemName + "\" without its associated save data"));
}
}
}
if (array2[l])
{
num4++;
}
if (array3[l])
{
num5++;
}
}
string text4 = (num6 - num).ToString();
if (num6 > num)
{
text4 = "+" + text4;
}
Plugin.Logger.LogInfo((object)$"Load | Items | Loaded {array.Length} items with a total value of {num6} ({text4})");
values = list2.ToArray();
data = list3.ToArray();
}
}
public static class FixItemRotation
{
public static Vector3[] LoadedItemRotations;
public static Dictionary<GrabbableObject, Vector3> NeedsItemRotation = new Dictionary<GrabbableObject, Vector3>();
public static List<Vector3> SavedItemRotations;
public static void PreSave()
{
SavedItemRotations = new List<Vector3>();
}
public static void Save(GrabbableObject[] grabbableObjects, int i)
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
GrabbableObject val = grabbableObjects[i];
SavedItemRotations.Add(((Component)val).transform.eulerAngles);
}
public static void PostSave(GameNetworkManager gameNetworkManager)
{
if (SavedItemRotations != null)
{
ES3.Save<Vector3[]>("SylviBlossom.SmartItemSaving_itemRotations", SavedItemRotations.ToArray(), gameNetworkManager.currentSaveFileName);
}
}
public static void PreLoad(int[] ids)
{
LoadedItemRotations = null;
NeedsItemRotation = new Dictionary<GrabbableObject, Vector3>();
string currentSaveFileName = GameNetworkManager.Instance.currentSaveFileName;
if (!General.LoadedParityCheck)
{
return;
}
if (!Config.SaveItemRotation.Value)
{
Plugin.Logger.LogInfo((object)"Load | Items | SaveItemRotation is disabled, skipping load item rotation");
return;
}
if (Compatibility.HasSaveItemRotations(out var pluginInfo) && !Config.ForceHandleSaveItemRotation.Value)
{
Plugin.Logger.LogInfo((object)$"Load | Items | Found mod {pluginInfo.Metadata.Name} v{pluginInfo.Metadata.Version}, skipping load item rotation");
return;
}
if (!ES3.KeyExists("SylviBlossom.SmartItemSaving_itemRotations", currentSaveFileName))
{
Plugin.Logger.LogWarning((object)"Load | Items | No item rotation save data found, skipping load item rotation");
return;
}
LoadedItemRotations = ES3.Load<Vector3[]>("SylviBlossom.SmartItemSaving_itemRotations", currentSaveFileName);
if (LoadedItemRotations.Length != ids.Length)
{
Plugin.Logger.LogError((object)$"Load | Items | Item count mismatch (Expected {LoadedItemRotations.Length}, got {ids.Length}), likely outdated save, skipping load item rotation");
LoadedItemRotations = null;
}
}
public static void Load(int i, GrabbableObject grabbableObject)
{
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
if (LoadedItemRotations != null)
{
if (i >= LoadedItemRotations.Length)
{
Plugin.Logger.LogError((object)"Load | Items | Item index outside bounds of saved rotations, this shouldn't happen");
return;
}
NeedsItemRotation.Add(grabbableObject, LoadedItemRotations[i]);
ApplyRotationTo(grabbableObject, LoadedItemRotations[i]);
}
}
public static void Apply(GrabbableObject grabbableObject)
{
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
if (((NetworkBehaviour)grabbableObject).IsServer && NeedsItemRotation.TryGetValue(grabbableObject, out var value))
{
ApplyRotationTo(grabbableObject, value);
NeedsItemRotation.Remove(grabbableObject);
}
}
private static void ApplyRotationTo(GrabbableObject grabbableObject, Vector3 eulerAngles)
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
grabbableObject.floorYRot = -1;
((Component)grabbableObject).transform.rotation = Quaternion.Euler(((Component)grabbableObject).transform.eulerAngles.x, eulerAngles.y, ((Component)grabbableObject).transform.eulerAngles.z);
}
}
public static class FixUnlockIds
{
public static void SaveFixUnlockIds(GameNetworkManager gameNetworkManager, List<int> unlocks)
{
string[] array = new string[unlocks.Count];
for (int i = 0; i < unlocks.Count; i++)
{
array[i] = StartOfRound.Instance.unlockablesList.unlockables[unlocks[i]].unlockableName;
}
ES3.Save<string[]>("SylviBlossom.SmartItemSaving_unlockNames", array, gameNetworkManager.currentSaveFileName);
Plugin.Logger.LogInfo((object)$"Save | Unlockables | Successfully saved {array.Length} unlocks");
}
public static void LoadFixUnlockIds(StartOfRound startOfRound, ref int[] unlocks)
{
string currentSaveFileName = GameNetworkManager.Instance.currentSaveFileName;
if (!General.LoadedParityCheck)
{
return;
}
if (!Config.FixItemIds.Value)
{
Plugin.Logger.LogInfo((object)"Load | Unlockables | FixItemIds is disabled, skipping unlockable id fixing");
return;
}
if (!ES3.KeyExists("SylviBlossom.SmartItemSaving_unlockNames", currentSaveFileName))
{
Plugin.Logger.LogWarning((object)"Load | Unlockables | No unlock name save data found, skipping unlockable id fixing");
return;
}
string[] array = ES3.Load<string[]>("SylviBlossom.SmartItemSaving_unlockNames", currentSaveFileName, new string[0]);
if (array.Length != unlocks.Length)
{
Plugin.Logger.LogError((object)$"Load | Unlockables | Unlocks count mismatch (Expected {array.Length}, got {unlocks.Length}), likely outdated save, skipping unlockable id fixing");
return;
}
List<int> list = new List<int>();
for (int i = 0; i < array.Length; i++)
{
string text = array[i];
int num = unlocks[i];
if (string.IsNullOrEmpty(text))
{
Plugin.Logger.LogWarning((object)$"Load | Unlockables | Found empty unlock name for unlock id {num}, loading normally");
list.Add(num);
continue;
}
string text2 = "";
if (startOfRound.unlockablesList.unlockables.Count > num && !string.IsNullOrEmpty(startOfRound.unlockablesList.unlockables[num].unlockableName))
{
text2 = "as \"" + startOfRound.unlockablesList.unlockables[num].unlockableName + "\"";
}
List<int> list2 = new List<int>();
for (int j = 0; j < startOfRound.unlockablesList.unlockables.Count; j++)
{
UnlockableItem val = startOfRound.unlockablesList.unlockables[j];
if (val.unlockableName.Equals(text, StringComparison.InvariantCultureIgnoreCase))
{
list2.Add(j);
}
}
if (list2.Count == 0)
{
if (Config.RemoveIfNotFound.Value)
{
Plugin.Logger.LogWarning((object)("Load | Unlockables | No unlock id found for unlock \"" + text + "\", removing item"));
continue;
}
Plugin.Logger.LogWarning((object)$"Load | Unlockables | No unlock id found for unlock \"{text}\", loading normally with id {num} {text2}");
list.Add(num);
continue;
}
if (list2.Count > 1)
{
string text3 = string.Join(",", list2);
if (list2.Contains(num))
{
Plugin.Logger.LogWarning((object)$"Load | Unlockables | Multiple ids ({text3}) found for unlock \"{text}\", loading normally with id {num} {text2}");
list.Add(num);
continue;
}
Plugin.Logger.LogWarning((object)$"Load | Unlockables | Multiple ids ({text3}) found for unlock \"{text}\", arbitrarily loading {list2[0]}");
}
if (num != list2[0])
{
if (num < startOfRound.unlockablesList.unlockables.Count && num >= 0)
{
Plugin.Logger.LogInfo((object)$"Load | Unlockables | Fixed unlock mismatch ({num}, \"{startOfRound.unlockablesList.unlockables[num].unlockableName}\" -> {list2[0]}, \"{text}\")");
}
else
{
Plugin.Logger.LogInfo((object)$"Load | Unlockables | Fixed unlock mismatch ({num}, unknown -> {list2[0]}, \"{text}\")");
}
list.Add(list2[0]);
}
else
{
list.Add(num);
}
}
unlocks = list.ToArray();
Plugin.Logger.LogInfo((object)$"Load | Unlockables | Loaded {list.Count} unlocks");
}
}
public static class General
{
public static int LoadedFormatVersion;
public static bool LoadedParityCheck;
public static void SaveInitialValues(GameNetworkManager gameNetworkManager)
{
ES3.Save<int>("SylviBlossom.SmartItemSaving_formatVersion", 2, gameNetworkManager.currentSaveFileName);
ES3.Save<int>("SylviBlossom.SmartItemSaving_parityStepsTaken", StartOfRound.Instance.gameStats.allStepsTaken, gameNetworkManager.currentSaveFileName);
}
public static void LoadInitialValues(StartOfRound startOfRound)
{
string currentSaveFileName = GameNetworkManager.Instance.currentSaveFileName;
if (!ES3.KeyExists("SylviBlossom.SmartItemSaving_formatVersion", currentSaveFileName))
{
LoadedFormatVersion = 0;
LoadedParityCheck = false;
Plugin.Logger.LogWarning((object)"Load | General | No SmartItemSaving save data found, skipping all");
return;
}
LoadedFormatVersion = ES3.Load<int>("SylviBlossom.SmartItemSaving_formatVersion", currentSaveFileName, 2);
int num = ES3.Load<int>("SylviBlossom.SmartItemSaving_parityStepsTaken", currentSaveFileName, startOfRound.gameStats.allStepsTaken);
if (num != startOfRound.gameStats.allStepsTaken)
{
LoadedParityCheck = false;
Plugin.Logger.LogWarning((object)$"Load | General | Steps Taken mismatch (Expected {num}, got {startOfRound.gameStats.allStepsTaken}), likely outdated save, skipping all");
}
else
{
LoadedParityCheck = true;
}
}
public static void LoadCreateBackup()
{
string currentSaveFileName = GameNetworkManager.Instance.currentSaveFileName;
if (Config.BackupOnLoad.Value && ES3.FileExists(currentSaveFileName))
{
Plugin.Logger.LogInfo((object)"Load | General | Creating save backup");
ES3.CreateBackup(currentSaveFileName);
}
}
public static void DeleteItemKeys(GameNetworkManager gameNetworkManager)
{
ES3.DeleteKey("SylviBlossom.SmartItemSaving_itemNames", gameNetworkManager.currentSaveFileName);
ES3.DeleteKey("SylviBlossom.SmartItemSaving_itemHasValue", gameNetworkManager.currentSaveFileName);
ES3.DeleteKey("SylviBlossom.SmartItemSaving_itemHasData", gameNetworkManager.currentSaveFileName);
ES3.DeleteKey("SylviBlossom.SmartItemSaving_itemRotations", gameNetworkManager.currentSaveFileName);
}
}
}