using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = "")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ItemRackMod { internal static class DefaultItemNameResolver { private static readonly string[] PreferredMemberNames = new string[8] { "itemName", "displayName", "itemDisplayName", "display_name", "name", "Name", "item_name", "display_name_text" }; private static readonly Dictionary CachedMembers = new Dictionary(); private static readonly Dictionary CanonicalItemAliases = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "explosive mine", "ItemMineExplosive" }, { "sledge hammer", "ItemMelee" }, { "hammer", "ItemMelee" }, { "inflatable hammer", "ItemMeleeInflatableHammer" }, { "shockwave mine", "ItemMineStun" }, { "duct taped granade", "ItemGrenadeDuctTaped" }, { "trapzap", "ItemMineTrigger" }, { "human granade", "ItemGrenadeHuman" }, { "granade", "ItemGrenadeExplosive" }, { "stun granade", "ItemGrenadeStun" }, { "shockwave granade", "ItemGrenadeShockwave" }, { "recharge drone", "ItemDroneBattery" }, { "feather drone", "ItemDroneFeather" }, { "roll drone", "ItemDroneTorque" }, { "zero gravity drone", "ItemDroneZeroGravity" }, { "indestructible drone", "ItemDroneIndestructible" }, { "zero gravity orb", "ItemOrbZeroGravity" } }; public static bool IsCanonicalPlatformName(string configuredName) { return !string.IsNullOrWhiteSpace(configuredName) && CanonicalItemAliases.ContainsKey(Normalize(configuredName)); } public static bool MatchesConfiguredName(string configuredName, PhysGrabObject pgo) { if ((Object)(object)pgo == (Object)null || string.IsNullOrWhiteSpace(configuredName)) { return false; } string text = Normalize(configuredName); if (string.IsNullOrEmpty(text)) { return false; } if (CanonicalItemAliases.TryGetValue(text, out var value)) { Component[] components = ((Component)pgo).GetComponents(); foreach (Component val in components) { if ((Object)(object)val != (Object)null && string.Equals(((object)val).GetType().Name, value, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } foreach (Component relevantComponent in GetRelevantComponents(pgo)) { if (!((Object)(object)relevantComponent == (Object)null)) { if (string.Equals(Normalize(((object)relevantComponent).GetType().Name), text, StringComparison.OrdinalIgnoreCase)) { return true; } if (TryReadNamedString(relevantComponent, out var value2) && string.Equals(Normalize(value2), text, StringComparison.OrdinalIgnoreCase)) { return true; } } } return (Object)(object)((Component)pgo).gameObject != (Object)null && string.Equals(Normalize(((Object)((Component)pgo).gameObject).name), text, StringComparison.OrdinalIgnoreCase); } public static bool TryGetItemName(PhysGrabObject pgo, out string name) { name = null; if ((Object)(object)pgo == (Object)null) { return false; } foreach (Component relevantComponent in GetRelevantComponents(pgo)) { if (TryReadNamedString(relevantComponent, out name) && !string.IsNullOrWhiteSpace(name)) { return true; } } name = (((Object)(object)((Component)pgo).gameObject != (Object)null) ? ((Object)((Component)pgo).gameObject).name : null); return !string.IsNullOrWhiteSpace(name); } public static IEnumerable GetItemAliases(PhysGrabObject pgo) { if ((Object)(object)pgo == (Object)null) { yield break; } HashSet yielded = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (Component component in GetRelevantComponents(pgo)) { if (!((Object)(object)component == (Object)null)) { string typeName = ((object)component).GetType().Name; if (!string.IsNullOrWhiteSpace(typeName) && yielded.Add(typeName)) { yield return typeName; } if (TryReadNamedString(component, out var value) && !string.IsNullOrWhiteSpace(value) && yielded.Add(value)) { yield return value; } value = null; } } if ((Object)(object)((Component)pgo).gameObject != (Object)null && yielded.Add(((Object)((Component)pgo).gameObject).name)) { yield return ((Object)((Component)pgo).gameObject).name; } } public static string Normalize(string value) { if (string.IsNullOrWhiteSpace(value)) { return string.Empty; } string text = value.Trim(); int num = text.IndexOf("(Clone)", StringComparison.OrdinalIgnoreCase); if (num >= 0) { text = text.Substring(0, num); } text = text.Replace("_", " ").Replace("-", " "); while (text.Contains(" ")) { text = text.Replace(" ", " "); } return text.Trim().ToLowerInvariant(); } private static IEnumerable GetRelevantComponents(PhysGrabObject pgo) { if ((Object)(object)pgo == (Object)null) { yield break; } Component[] componentsInChildren = ((Component)pgo).GetComponentsInChildren(true); foreach (Component component in componentsInChildren) { if (!((Object)(object)component == (Object)null)) { string typeName = ((object)component).GetType().Name; if (typeName.Equals("Item", StringComparison.OrdinalIgnoreCase) || typeName.Equals("ItemAttributes", StringComparison.OrdinalIgnoreCase) || typeName.Equals("ItemMelee", StringComparison.OrdinalIgnoreCase) || typeName.StartsWith("ItemMelee", StringComparison.OrdinalIgnoreCase) || typeName.StartsWith("ItemDrone", StringComparison.OrdinalIgnoreCase) || typeName.StartsWith("ItemGrenade", StringComparison.OrdinalIgnoreCase) || typeName.StartsWith("ItemMine", StringComparison.OrdinalIgnoreCase) || typeName.StartsWith("ItemOrb", StringComparison.OrdinalIgnoreCase)) { yield return component; } } } Transform current = ((Component)pgo).transform.parent; while ((Object)(object)current != (Object)null) { Component[] components = ((Component)current).GetComponents(); foreach (Component component2 in components) { if (!((Object)(object)component2 == (Object)null)) { string typeName2 = ((object)component2).GetType().Name; if (typeName2.Equals("Item", StringComparison.OrdinalIgnoreCase) || typeName2.Equals("ItemAttributes", StringComparison.OrdinalIgnoreCase) || typeName2.StartsWith("ItemDrone", StringComparison.OrdinalIgnoreCase) || typeName2.StartsWith("ItemGrenade", StringComparison.OrdinalIgnoreCase) || typeName2.StartsWith("ItemMine", StringComparison.OrdinalIgnoreCase) || typeName2.StartsWith("ItemOrb", StringComparison.OrdinalIgnoreCase)) { yield return component2; } } } current = current.parent; } } private static bool TryReadNamedString(object target, out string value) { value = null; if (target == null) { return false; } Type type = target.GetType(); MemberInfo[] members = GetMembers(type); string[] preferredMemberNames = PreferredMemberNames; foreach (string value2 in preferredMemberNames) { MemberInfo[] array = members; foreach (MemberInfo memberInfo in array) { if (memberInfo.Name.Equals(value2, StringComparison.OrdinalIgnoreCase) && TryGetString(target, memberInfo, out value) && !string.IsNullOrWhiteSpace(value)) { return true; } } } MemberInfo[] array2 = members; foreach (MemberInfo memberInfo2 in array2) { if ((memberInfo2.Name.IndexOf("name", StringComparison.OrdinalIgnoreCase) >= 0 || memberInfo2.Name.IndexOf("display", StringComparison.OrdinalIgnoreCase) >= 0) && TryGetString(target, memberInfo2, out value) && !string.IsNullOrWhiteSpace(value)) { return true; } } return false; } private static MemberInfo[] GetMembers(Type type) { if (CachedMembers.TryGetValue(type, out var value)) { return value; } List list = new List(); list.AddRange(type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)); list.AddRange(type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)); value = list.ToArray(); CachedMembers[type] = value; return value; } private static bool TryGetString(object target, MemberInfo member, out string value) { value = null; try { if (member is FieldInfo fieldInfo && fieldInfo.FieldType == typeof(string)) { value = fieldInfo.GetValue(target) as string; return true; } if (member is PropertyInfo propertyInfo && propertyInfo.PropertyType == typeof(string) && propertyInfo.CanRead && propertyInfo.GetIndexParameters().Length == 0) { value = propertyInfo.GetValue(target, null) as string; return true; } } catch { } return false; } } public class DefaultItemPlacement : MonoBehaviour { private ItemRackController _controller; private readonly List _assignments = new List(); private readonly HashSet _loggedMissingSlots = new HashSet(); private readonly HashSet _placedDefaultObjects = new HashSet(); private readonly HashSet _inventoryObjectIds = new HashSet(); private float _scanTimer; private bool _loggedInitialScan; private bool _placementComplete; private float _startupUntil; private const float FastScanInterval = 0.25f; private const float FastScanSeconds = 5f; private const float StartupPlacementSeconds = 5f; public void Init(ItemRackController controller) { _controller = controller; _assignments.Clear(); _loggedMissingSlots.Clear(); _placedDefaultObjects.Clear(); _inventoryObjectIds.Clear(); _scanTimer = 0f; _loggedInitialScan = false; _placementComplete = false; _startupUntil = Time.time + 5f; foreach (DefaultAssignment item in ModConfig.ParseSlotAssignments()) { _assignments.Add(item); } Plugin.Log.LogInfo((object)$"Default item placement initialized with {_assignments.Count} preferred item slot(s)."); ScanNow(); } private void Update() { if (!_placementComplete && !(Time.time >= _startupUntil)) { _scanTimer -= Time.deltaTime; if (!(_scanTimer > 0f)) { _scanTimer = 0.25f; ScanNow(); } } } private void ScanNow() { if ((Object)(object)_controller == (Object)null || _assignments.Count == 0 || !SemiFunc.IsMasterClientOrSingleplayer()) { return; } CaptureInventoryItems(); _placedDefaultObjects.RemoveWhere((PhysGrabObject pgo) => (Object)(object)pgo == (Object)null || pgo.dead); PhysGrabObject[] array = Object.FindObjectsOfType(); if (array == null || array.Length == 0) { return; } List list = new List(); PhysGrabObject[] array2 = array; foreach (PhysGrabObject val in array2) { if (!((Object)(object)val == (Object)null) && !val.dead && !val.grabbed && !_placedDefaultObjects.Contains(val) && !_inventoryObjectIds.Contains(((Object)val).GetInstanceID()) && !((Object)(object)((Component)val).GetComponent() != (Object)null)) { list.Add(val); } } ProcessPlatformGroup(list, "MinePlatform"); ProcessPlatformGroup(list, "DronePlatform"); ProcessPlatformGroup(list, "GrenadePlatform"); foreach (DefaultAssignment assignment in _assignments) { if (!IsPlatformAssignment(assignment.SlotKey)) { TryPlaceAssignment(assignment, list); } } if (AreAllAssignmentsSatisfied()) { _placementComplete = true; Plugin.Log.LogInfo((object)"Automatic rack/platform placement completed; scene-wide startup scans stopped."); } if (!_loggedInitialScan) { _loggedInitialScan = true; Plugin.Log.LogInfo((object)"Automatic rack/platform placement is active for the startup window. Platform priority: MinePlatform -> DronePlatform -> GrenadePlatform; exact item matching is enforced and fuzzy matching is disabled."); } } private void ProcessPlatformGroup(List candidates, string platformName) { foreach (DefaultAssignment assignment in _assignments) { if (IsAssignmentOnPlatform(assignment, platformName)) { TryPlaceAssignment(assignment, candidates); } } } private static bool IsAssignmentOnPlatform(DefaultAssignment assignment, string platformName) { if (assignment == null || string.IsNullOrEmpty(assignment.SlotKey)) { return false; } return assignment.SlotKey.StartsWith(platformName + ":", StringComparison.OrdinalIgnoreCase); } private void TryPlaceAssignment(DefaultAssignment assignment, List candidates) { if (!_controller.TryGetSlot(assignment.SlotKey, out var slot)) { int hashCode = StringComparer.OrdinalIgnoreCase.GetHashCode(assignment.SlotKey); if (_loggedMissingSlots.Add(hashCode)) { Plugin.Log.LogWarning((object)("Default item assignment points to missing slot '" + assignment.SlotKey + "'. Check the platform dimensions and SlotAssignments.")); } return; } if ((Object)(object)slot.Occupant != (Object)null) { if (DefaultItemNameResolver.MatchesConfiguredName(assignment.ItemName, slot.Occupant)) { _placedDefaultObjects.Add(slot.Occupant); return; } slot.DetachForAutomaticMove(); } PhysGrabObject val = FindExactCandidate(assignment.ItemName, candidates); if (!((Object)(object)val == (Object)null)) { ItemRackSlot itemRackSlot = _controller.FindSlotContaining(val); if ((Object)(object)itemRackSlot != (Object)null && (Object)(object)itemRackSlot != (Object)(object)slot) { itemRackSlot.DetachForAutomaticMove(); } if (slot.TrySnapItem(val, allowReplace: false, applyConfiguredOrientation: true, bypassStartupFilter: true)) { _placedDefaultObjects.Add(val); Plugin.Log.LogInfo((object)("Default item '" + assignment.ItemName + "' placed in " + assignment.SlotKey + ".")); } } } private bool AreAllAssignmentsSatisfied() { if (_assignments.Count == 0) { return true; } foreach (DefaultAssignment assignment in _assignments) { if (assignment != null) { if (!_controller.TryGetSlot(assignment.SlotKey, out var slot)) { return false; } if ((Object)(object)slot.Occupant == (Object)null || !DefaultItemNameResolver.MatchesConfiguredName(assignment.ItemName, slot.Occupant)) { return false; } } } return true; } private void CaptureInventoryItems() { try { InventorySpot[] array = Resources.FindObjectsOfTypeAll(); if (array == null) { return; } InventorySpot[] array2 = array; foreach (InventorySpot val in array2) { if ((Object)(object)val == (Object)null) { continue; } PhysGrabObject[] componentsInChildren = ((Component)val).GetComponentsInChildren(true); PhysGrabObject[] array3 = componentsInChildren; foreach (PhysGrabObject val2 in array3) { if ((Object)(object)val2 != (Object)null) { _inventoryObjectIds.Add(((Object)val2).GetInstanceID()); } } } } catch (Exception ex) { Plugin.Log.LogDebug((object)("Could not inspect inventory items: " + ex.Message)); } } private static bool IsPlatformAssignment(string slotKey) { return slotKey.StartsWith("DronePlatform:", StringComparison.OrdinalIgnoreCase) || slotKey.StartsWith("GrenadePlatform:", StringComparison.OrdinalIgnoreCase) || slotKey.StartsWith("MinePlatform:", StringComparison.OrdinalIgnoreCase); } private PhysGrabObject FindExactCandidate(string configuredName, List candidates) { foreach (PhysGrabObject candidate in candidates) { if ((Object)(object)candidate == (Object)null || candidate.dead || candidate.grabbed || _placedDefaultObjects.Contains(candidate) || !DefaultItemNameResolver.MatchesConfiguredName(configuredName, candidate)) { continue; } return candidate; } return null; } public void ResetPlacementBookkeeping() { _placedDefaultObjects.Clear(); _inventoryObjectIds.Clear(); _loggedMissingSlots.Clear(); _scanTimer = 0f; _loggedInitialScan = false; _placementComplete = false; _startupUntil = Time.time + 5f; } } internal sealed class DefaultAssignment { public string SlotKey; public string ItemName; } public class ItemDisplayPlatform : MonoBehaviour { public int Rows { get; private set; } public int Columns { get; private set; } public void Setup(int rows, int columns) { Rows = Mathf.Max(1, rows); Columns = Mathf.Max(1, columns); } } internal static class ItemOrientation { private static readonly Dictionary _rotations = new Dictionary(StringComparer.OrdinalIgnoreCase); private static bool _loaded; public static void Apply(PhysGrabObject pgo, Transform slot) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)pgo == (Object)null) && !((Object)(object)slot == (Object)null)) { EnsureLoaded(); if (DefaultItemNameResolver.TryGetItemName(pgo, out var name) && _rotations.TryGetValue(DefaultItemNameResolver.Normalize(name), out var value)) { ((Component)pgo).transform.localRotation = Quaternion.Euler(value); } } } private static void EnsureLoaded() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) if (_loaded) { return; } _loaded = true; foreach (KeyValuePair item in ModConfig.ParseItemOrientations()) { _rotations[DefaultItemNameResolver.Normalize(item.Key)] = item.Value; } } } public class ItemRackController : MonoBehaviour { private readonly List _slots = new List(); private readonly Dictionary _slotByKey = new Dictionary(StringComparer.OrdinalIgnoreCase); private DefaultItemPlacement _defaultPlacement; private bool _initialized; public IReadOnlyList Slots => _slots; public void Init(Transform anchor) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) if (!_initialized) { _initialized = true; Plugin.Log.LogInfo((object)"ItemRackController initialization started."); if (ModConfig.EnableLeftWall.Value) { BuildWall("Left", anchor, new Vector3(ModConfig.LeftOffsetX.Value, ModConfig.LeftOffsetY.Value, ModConfig.LeftOffsetZ.Value), ModConfig.LeftRotationY.Value); } if (ModConfig.EnableRightWall.Value) { BuildWall("Right", anchor, new Vector3(ModConfig.RightOffsetX.Value, ModConfig.RightOffsetY.Value, ModConfig.RightOffsetZ.Value), ModConfig.RightRotationY.Value); } if (ModConfig.EnableGrenadePlatform.Value) { BuildItemPlatform(anchor, "GrenadePlatform", 3, 4, new Vector3(ModConfig.GrenadePlatformOffsetX.Value, ModConfig.GrenadePlatformOffsetY.Value, ModConfig.GrenadePlatformOffsetZ.Value), ModConfig.GrenadePlatformRotationY.Value, ModConfig.GrenadePlatformSpacingX.Value, ModConfig.GrenadePlatformSpacingZ.Value, new Vector3(ModConfig.GrenadePlatformSizeX.Value, ModConfig.GrenadePlatformSizeY.Value, ModConfig.GrenadePlatformSizeZ.Value)); } if (ModConfig.EnableDronePlatform.Value) { BuildItemPlatform(anchor, "DronePlatform", 2, 3, new Vector3(ModConfig.DronePlatformOffsetX.Value, ModConfig.DronePlatformOffsetY.Value, ModConfig.DronePlatformOffsetZ.Value), ModConfig.DronePlatformRotationY.Value, ModConfig.DronePlatformSpacingX.Value, ModConfig.DronePlatformSpacingZ.Value, new Vector3(ModConfig.DronePlatformSizeX.Value, ModConfig.DronePlatformSizeY.Value, ModConfig.DronePlatformSizeZ.Value)); } if (ModConfig.EnableMinePlatform.Value) { BuildItemPlatform(anchor, "MinePlatform", 2, 6, new Vector3(ModConfig.MinePlatformOffsetX.Value, ModConfig.MinePlatformOffsetY.Value, ModConfig.MinePlatformOffsetZ.Value), ModConfig.MinePlatformRotationY.Value, ModConfig.MinePlatformSpacingX.Value, ModConfig.MinePlatformSpacingZ.Value, new Vector3(ModConfig.MinePlatformSizeX.Value, ModConfig.MinePlatformSizeY.Value, ModConfig.MinePlatformSizeZ.Value)); } _defaultPlacement = ((Component)this).gameObject.GetComponent(); if ((Object)(object)_defaultPlacement == (Object)null) { _defaultPlacement = ((Component)this).gameObject.AddComponent(); } _defaultPlacement.Init(this); Plugin.Log.LogInfo((object)$"Built {_slots.Count} rack/platform slot(s) total inside the truck."); Plugin.Log.LogInfo((object)"Horizontal item platforms initialized. Platform cells are non-solid and use the same snap/hold system as rack shelves."); } } private void BuildWall(string wallName, Transform anchor, Vector3 localOffset, float extraRotationY) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: 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) GameObject val = new GameObject("ItemRackWall_" + wallName); val.transform.SetParent(anchor, false); val.transform.localPosition = localOffset; val.transform.localRotation = Quaternion.Euler(0f, extraRotationY, 0f); int num = Mathf.Max(1, ModConfig.Rows.Value); int num2 = Mathf.Max(1, ModConfig.Columns.Value); float value = ModConfig.SpacingHorizontal.Value; float value2 = ModConfig.SpacingVertical.Value; float num3 = (float)(num2 - 1) * value; float num4 = (float)(num - 1) * value2; Vector3 localPosition = default(Vector3); for (int i = 0; i < num; i++) { for (int j = 0; j < num2; j++) { int index = i * num2 + j + 1; ((Vector3)(ref localPosition))..ctor((0f - num3) / 2f + (float)j * value, (0f - num4) / 2f + (float)i * value2, 0f); BuildSlot(val.transform, wallName, i + 1, j + 1, index, localPosition, platform: false, Vector3.zero); } } Plugin.Log.LogInfo((object)$"Built {wallName} wall: {num} row(s) x {num2} column(s)."); } private void BuildSlot(Transform parent, string wallName, int row, int column, int index, Vector3 localPosition, bool platform, Vector3 cellSize) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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_0081: 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_011a: Unknown result type (might be due to invalid IL or missing references) string text = ModConfig.MakeSlotKey(wallName, row, column); GameObject val = new GameObject($"ItemRackSlot_{wallName}_{index}"); val.transform.SetParent(parent, false); val.transform.localPosition = localPosition; val.transform.localRotation = Quaternion.identity; SphereCollider val2 = val.AddComponent(); ((Collider)val2).isTrigger = true; val2.radius = (platform ? Mathf.Max(ModConfig.SlotRadius.Value, Mathf.Max(cellSize.x, Mathf.Max(cellSize.y, cellSize.z)) * 0.5f) : ModConfig.SlotRadius.Value); ItemRackSlot itemRackSlot = val.AddComponent(); itemRackSlot.Setup(this, wallName, row, column, text); string configuredItemName = GetConfiguredItemName(text); if (!string.IsNullOrWhiteSpace(configuredItemName)) { itemRackSlot.SetInitialItemBinding(configuredItemName); } _slots.Add(itemRackSlot); _slotByKey[text] = itemRackSlot; if (ModConfig.ShowVisualMarkers.Value) { if (platform) { CreatePlatformMarker(val.transform, cellSize); } else { CreateVisualMarker(val.transform); } } } private void BuildItemPlatform(Transform anchor, string platformName, int rows, int columns, Vector3 localOffset, float rotationY, float spacingX, float spacingZ, Vector3 cellSize) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Expected O, but got Unknown //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("ItemRack_" + platformName); val.transform.SetParent(anchor, false); val.transform.localPosition = localOffset; val.transform.localRotation = Quaternion.Euler(0f, rotationY, 0f); float num = (float)(columns - 1) * spacingX; float num2 = (float)(rows - 1) * spacingZ; Vector3 localPosition = default(Vector3); for (int i = 0; i < rows; i++) { for (int j = 0; j < columns; j++) { ((Vector3)(ref localPosition))..ctor((0f - num) / 2f + (float)j * spacingX, 0f, (0f - num2) / 2f + (float)i * spacingZ); string text = ModConfig.MakePlatformSlotKey(platformName, i + 1, j + 1); GameObject val2 = new GameObject($"{platformName}_Slot_{i + 1}_{j + 1}"); val2.transform.SetParent(val.transform, false); val2.transform.localPosition = localPosition; val2.transform.localRotation = Quaternion.identity; SphereCollider val3 = val2.AddComponent(); ((Collider)val3).isTrigger = true; val3.radius = Mathf.Max(ModConfig.SlotRadius.Value, Mathf.Max(cellSize.x, Mathf.Max(cellSize.y, cellSize.z)) * 0.5f); ItemRackSlot itemRackSlot = val2.AddComponent(); itemRackSlot.Setup(this, platformName, i + 1, j + 1, text); string configuredItemName = GetConfiguredItemName(text); if (!string.IsNullOrWhiteSpace(configuredItemName)) { itemRackSlot.SetInitialItemBinding(configuredItemName); } _slots.Add(itemRackSlot); _slotByKey[text] = itemRackSlot; if (ModConfig.ShowVisualMarkers.Value) { CreatePlatformMarker(val2.transform, cellSize); } } } Plugin.Log.LogInfo((object)($"SUCCESS: Built {platformName} at local position {localOffset}, " + $"rotation Y={rotationY}, {rows} row(s) x {columns} column(s).")); } public bool TryGetSlot(string key, out ItemRackSlot slot) { return _slotByKey.TryGetValue(key, out slot); } public ItemRackSlot FindSlotContaining(PhysGrabObject pgo) { if ((Object)(object)pgo == (Object)null) { return null; } foreach (ItemRackSlot slot in _slots) { if ((Object)(object)slot != (Object)null && (Object)(object)slot.Occupant == (Object)(object)pgo) { return slot; } } return null; } private static string GetConfiguredItemName(string slotKey) { foreach (DefaultAssignment item in ModConfig.ParseSlotAssignments()) { if (string.Equals(item.SlotKey, slotKey, StringComparison.OrdinalIgnoreCase)) { return item.ItemName; } } return null; } private void CreateVisualMarker(Transform parent) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)val).name = "SlotMarker"; Collider component = val.GetComponent(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } val.transform.SetParent(parent, false); val.transform.localPosition = Vector3.zero; float num = ModConfig.SlotRadius.Value * 1.6f; val.transform.localScale = new Vector3(num, num, 0.015f); ApplyMarkerMaterial(val); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not create slot visual marker: " + ex.Message)); } } private void CreatePlatformMarker(Transform parent, Vector3 cellSize) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)val).name = "PlatformSlotMarker"; Collider component = val.GetComponent(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } val.transform.SetParent(parent, false); val.transform.localPosition = Vector3.zero; val.transform.localScale = cellSize; ApplyMarkerMaterial(val); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not create platform visual marker: " + ex.Message)); } } private static void ApplyMarkerMaterial(GameObject marker) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) Renderer component = marker.GetComponent(); if (!((Object)(object)component == (Object)null)) { component.shadowCastingMode = (ShadowCastingMode)0; component.receiveShadows = false; if ((Object)(object)component.material != (Object)null) { component.material.color = new Color(0.25f, 0.9f, 1f, 0.55f); } } } public void ResetForNewScene() { foreach (ItemRackSlot slot in _slots) { if ((Object)(object)slot != (Object)null) { slot.ResetForNewScene(); } } if ((Object)(object)_defaultPlacement != (Object)null) { _defaultPlacement.ResetPlacementBookkeeping(); } Plugin.Log.LogInfo((object)"ItemRackMod reset startup platform bindings for a new scene."); } public void OnSlotFreed(ItemRackSlot slot) { } } public class ItemRackSlot : MonoBehaviour { private ItemRackController _controller; private string _configuredInitialItemName; private float _initialBindingReleaseAt = -1f; private const float InitialBindingSeconds = 5f; private float _kinematicRefreshTimer; private const float KinematicRefreshInterval = 0.25f; private const float KinematicHoldSeconds = 0.75f; public string WallName { get; private set; } public int Row { get; private set; } public int Column { get; private set; } public string SlotKey { get; private set; } public PhysGrabObject Occupant { get; private set; } public string InitialItemName { get; private set; } public bool IsPlatformSlot { get; private set; } public bool InitialBindingActive { get; private set; } public void Setup(ItemRackController controller, string wallName, int row, int column, string slotKey) { _controller = controller; WallName = wallName; Row = row; Column = column; SlotKey = slotKey; IsPlatformSlot = IsPlatformName(wallName); } public void SetInitialItemBinding(string itemName) { if (!string.IsNullOrWhiteSpace(itemName)) { _configuredInitialItemName = itemName.Trim(); InitialItemName = _configuredInitialItemName; InitialBindingActive = true; _initialBindingReleaseAt = Time.time + 5f; Plugin.Log.LogInfo((object)$"Startup item filter armed for {SlotKey}: '{InitialItemName}' for {5f:0.#} seconds."); } } public void ResetForNewScene() { if ((Object)(object)Occupant != (Object)null && (Object)(object)((Component)Occupant).transform.parent == (Object)(object)((Component)this).transform) { ((Component)Occupant).transform.SetParent((Transform)null, true); } Occupant = null; _kinematicRefreshTimer = 0f; if (!string.IsNullOrWhiteSpace(_configuredInitialItemName)) { InitialItemName = _configuredInitialItemName; InitialBindingActive = true; _initialBindingReleaseAt = Time.time + 5f; } } public bool AcceptsItemForInitialBinding(PhysGrabObject pgo) { if (!InitialBindingActive) { return true; } return !string.IsNullOrWhiteSpace(InitialItemName) && DefaultItemNameResolver.MatchesConfiguredName(InitialItemName, pgo); } private static bool IsPlatformName(string name) { return string.Equals(name, "DronePlatform", StringComparison.OrdinalIgnoreCase) || string.Equals(name, "GrenadePlatform", StringComparison.OrdinalIgnoreCase) || string.Equals(name, "MinePlatform", StringComparison.OrdinalIgnoreCase); } private void Update() { if (InitialBindingActive && _initialBindingReleaseAt > 0f && Time.time >= _initialBindingReleaseAt) { InitialBindingActive = false; InitialItemName = null; _initialBindingReleaseAt = -1f; Plugin.Log.LogInfo((object)("Initial item filter expired for " + SlotKey + "; slot is now universal.")); } if ((Object)(object)Occupant == (Object)null) { return; } if (Occupant.dead || Occupant.grabbed) { ReleaseOccupant(); } else if (SemiFunc.IsMasterClientOrSingleplayer()) { _kinematicRefreshTimer -= Time.deltaTime; if (!(_kinematicRefreshTimer > 0f)) { _kinematicRefreshTimer = 0.25f; MaintainOccupant(); } } } private void OnTriggerStay(Collider other) { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Occupant != (Object)null || !SemiFunc.IsMasterClientOrSingleplayer()) { return; } PhysGrabObject val = FindPhysGrabObject(other); if ((Object)(object)val == (Object)null || val.dead || val.grabbed || (Object)(object)((Component)val).GetComponent() != (Object)null || (IsPlatformSlot && InitialBindingActive) || !AcceptsItemForInitialBinding(val)) { return; } if ((Object)(object)val.rb != (Object)null) { float value = ModConfig.MaxSnapSpeed.Value; Vector3 velocity = val.rb.velocity; if (((Vector3)(ref velocity)).sqrMagnitude > value * value) { return; } } TrySnapItem(val); } private static PhysGrabObject FindPhysGrabObject(Collider other) { if ((Object)(object)other == (Object)null) { return null; } PhysGrabObject component = ((Component)other).GetComponent(); if ((Object)(object)component != (Object)null) { return component; } component = ((Component)other).GetComponentInParent(); if ((Object)(object)component != (Object)null) { return component; } if ((Object)(object)other.attachedRigidbody != (Object)null) { component = ((Component)other.attachedRigidbody).GetComponent(); if ((Object)(object)component != (Object)null) { return component; } component = ((Component)other.attachedRigidbody).GetComponentInParent(); } return component; } public bool TrySnapItem(PhysGrabObject pgo, bool allowReplace = false, bool applyConfiguredOrientation = true, bool bypassStartupFilter = false) { if ((Object)(object)pgo == (Object)null || pgo.dead || pgo.grabbed) { return false; } if ((Object)(object)((Component)pgo).GetComponent() != (Object)null) { return false; } if (!bypassStartupFilter && !AcceptsItemForInitialBinding(pgo)) { return false; } if ((Object)(object)Occupant != (Object)null) { if (!allowReplace) { return false; } ReleaseOccupant(); if ((Object)(object)Occupant != (Object)null) { return false; } } PhotonView component = ((Component)pgo).GetComponent(); if ((Object)(object)component != (Object)null && !component.IsMine) { component.RequestOwnership(); } Occupant = pgo; _kinematicRefreshTimer = 0f; ((Component)pgo).transform.SetParent(((Component)this).transform, false); MaintainOccupant(applyConfiguredOrientation); return (Object)(object)Occupant == (Object)(object)pgo; } public void DetachForAutomaticMove() { if (!((Object)(object)Occupant == (Object)null)) { if ((Object)(object)((Component)Occupant).transform.parent == (Object)(object)((Component)this).transform) { ((Component)Occupant).transform.SetParent((Transform)null, true); } Occupant = null; _kinematicRefreshTimer = 0f; _controller?.OnSlotFreed(this); } } private void MaintainOccupant(bool applyConfiguredOrientation = true) { //IL_003f: 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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: 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_0097: 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_00af: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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 ((Object)(object)Occupant == (Object)null) { return; } if (Occupant.dead || Occupant.grabbed) { ReleaseOccupant(); return; } Quaternion val = Quaternion.identity; if (applyConfiguredOrientation) { val = GetDesiredLocalRotation(); } Quaternion val2 = ((Component)this).transform.rotation * val; Occupant.OverrideKinematic(0.75f); ((Component)Occupant).transform.localPosition = Vector3.zero; ((Component)Occupant).transform.localRotation = val; Occupant.Teleport(((Component)this).transform.position, val2); } private Quaternion GetDesiredLocalRotation() { //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_002f: 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) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Occupant == (Object)null) { return Quaternion.identity; } if (!DefaultItemNameResolver.TryGetItemName(Occupant, out var name)) { return Quaternion.identity; } if (ModConfig.TryGetItemOrientation(name, out var euler)) { return Quaternion.Euler(euler); } return Quaternion.identity; } private void ReleaseOccupant() { if ((Object)(object)Occupant != (Object)null && (Object)(object)((Component)Occupant).transform.parent == (Object)(object)((Component)this).transform) { ((Component)Occupant).transform.SetParent((Transform)null, true); } Occupant = null; _kinematicRefreshTimer = 0f; _controller?.OnSlotFreed(this); } } internal static class ModConfig { public static ConfigEntry Rows; public static ConfigEntry Columns; public static ConfigEntry SpacingHorizontal; public static ConfigEntry SpacingVertical; public static ConfigEntry EnableLeftWall; public static ConfigEntry EnableRightWall; public static ConfigEntry SlotRadius; public static ConfigEntry MaxSnapSpeed; public static ConfigEntry ShowVisualMarkers; public static ConfigEntry SlotAssignments; public static ConfigEntry ItemOrientations; private static readonly Dictionary CachedItemOrientations = new Dictionary(StringComparer.OrdinalIgnoreCase); public static ConfigEntry LeftOffsetX; public static ConfigEntry LeftOffsetY; public static ConfigEntry LeftOffsetZ; public static ConfigEntry LeftRotationY; public static ConfigEntry RightOffsetX; public static ConfigEntry RightOffsetY; public static ConfigEntry RightOffsetZ; public static ConfigEntry RightRotationY; public static ConfigEntry EnableGrenadePlatform; public static ConfigEntry GrenadePlatformOffsetX; public static ConfigEntry GrenadePlatformOffsetY; public static ConfigEntry GrenadePlatformOffsetZ; public static ConfigEntry GrenadePlatformRotationY; public static ConfigEntry GrenadePlatformSpacingX; public static ConfigEntry GrenadePlatformSpacingZ; public static ConfigEntry GrenadePlatformSizeX; public static ConfigEntry GrenadePlatformSizeY; public static ConfigEntry GrenadePlatformSizeZ; public static ConfigEntry EnableDronePlatform; public static ConfigEntry DronePlatformOffsetX; public static ConfigEntry DronePlatformOffsetY; public static ConfigEntry DronePlatformOffsetZ; public static ConfigEntry DronePlatformRotationY; public static ConfigEntry DronePlatformSpacingX; public static ConfigEntry DronePlatformSpacingZ; public static ConfigEntry DronePlatformSizeX; public static ConfigEntry DronePlatformSizeY; public static ConfigEntry DronePlatformSizeZ; public static ConfigEntry EnableMinePlatform; public static ConfigEntry MinePlatformOffsetX; public static ConfigEntry MinePlatformOffsetY; public static ConfigEntry MinePlatformOffsetZ; public static ConfigEntry MinePlatformRotationY; public static ConfigEntry MinePlatformSpacingX; public static ConfigEntry MinePlatformSpacingZ; public static ConfigEntry MinePlatformSizeX; public static ConfigEntry MinePlatformSizeY; public static ConfigEntry MinePlatformSizeZ; public static void Init(ConfigFile config) { Rows = config.Bind("Rack", "Rows", 2, "Rows per wall (vertical, floor-to-ceiling)."); Columns = config.Bind("Rack", "Columns", 7, "Columns per wall (along the wall)."); SpacingHorizontal = config.Bind("Rack", "SpacingHorizontal", 0.8000002f, "Distance between columns, in meters."); SpacingVertical = config.Bind("Rack", "SpacingVertical", 1.099999f, "Distance between rows, in meters."); EnableLeftWall = config.Bind("Rack", "EnableLeftWall", true, "Build a rack on the left wall."); EnableRightWall = config.Bind("Rack", "EnableRightWall", true, "Build a rack on the right wall."); SlotRadius = config.Bind("Rack", "SlotRadius", 0.02000006f, "Radius of each slot's detection trigger, in meters."); MaxSnapSpeed = config.Bind("Rack", "MaxSnapSpeed", 3.5f, "Items moving faster than this (m/s) will not snap into a slot."); ShowVisualMarkers = config.Bind("Rack", "ShowVisualMarkers", true, "Draw the same thin cyan marker at each empty rack/platform slot."); SlotAssignments = config.Bind("Rack.ItemAssignments", "SlotAssignments", "Right:1:1=Inflatable Hammer,Right:1:2=Baseball Bat,Right:1:3=Zero Gravity Staff,Right:1:4=Roll Staff,Right:1:5=Void Staff,Right:1:6=Rubber Duck,Right:1:7=semibot walkie,Right:2:1=Sword,Right:2:2=Frying Pan,Right:2:3=ProdZap,Right:2:4=Sledge Hammer,Right:2:7=semibot walkie,Left:1:1=C.A.R.T. Cannon,Left:1:2=Defibro,Left:1:3=Extraction Tracker,Left:1:4=Tranq Gun,Left:1:5=Shotgun,Left:1:6=Gun,Left:1:7=Pulse Pistol,Left:2:1=C.A.R.T. Laser,Left:2:2=Leaf Blower,Left:2:3=Duck Bucket,Left:2:4=Valuable Tracker,Left:2:5=Photon Blaster,Left:2:6=Boltzap,Left:2:7=Phase Bridge,DronePlatform:1:1=zero gravity drone,DronePlatform:1:2=zero gravity orb,DronePlatform:1:3=recharge drone,DronePlatform:2:1=indestructible drone,DronePlatform:2:2=roll drone,DronePlatform:2:3=feather drone,GrenadePlatform:1:1=grenade,GrenadePlatform:1:2=human grenade,GrenadePlatform:1:3=stun grenade,GrenadePlatform:1:4=shockwave mine,GrenadePlatform:2:1=grenade,GrenadePlatform:2:2=human grenade,GrenadePlatform:2:3=stun grenade,GrenadePlatform:2:4=shockwave mine,GrenadePlatform:3:1=grenade,GrenadePlatform:3:2=human grenade,GrenadePlatform:3:3=stun grenade,GrenadePlatform:3:4=shockwave mine,MinePlatform:1:1=explosive mine,MinePlatform:1:2=explosive mine,MinePlatform:1:3=explosive mine,MinePlatform:1:4=trapzap,MinePlatform:1:5=trapzap,MinePlatform:1:6=trapzap,MinePlatform:2:1=shockwave grenade,MinePlatform:2:2=shockwave grenade,MinePlatform:2:3=shockwave grenade,MinePlatform:2:4=duct taped grenade,MinePlatform:2:5=duct taped grenade,MinePlatform:2:6=duct taped grenade", "Default locations for wall racks and the three horizontal item platforms. Platform assignments use stable game component aliases."); EnsurePlatformAssignments(); ItemOrientations = config.Bind("Rack.ItemAssignments", "ItemOrientations", "Boltzap=90,0,0;Photon Blaster=90,0,0;Valuable Tracker=90,0,0;Leaf Blower=90,0,0;Pulse Pistol=90,0,0;Gun=90,0,0;Shotgun=90,0,0;Tranq Gun=90,0,0;Extraction Tracker=90,0,0", "Extra local Euler rotation for automatically placed rack items."); RebuildItemOrientationCache(); LeftOffsetX = config.Bind("Rack.LeftWall", "OffsetX", 1.399298f, "Local X offset of the left rack from TruckSafetySpawnPoint."); LeftOffsetY = config.Bind("Rack.LeftWall", "OffsetY", 0.8999991f, "Local Y offset of the left rack."); LeftOffsetZ = config.Bind("Rack.LeftWall", "OffsetZ", -2f, "Local Z offset of the left rack."); LeftRotationY = config.Bind("Rack.LeftWall", "RotationY", -3.650784E-06f, "Extra Y rotation for the left rack."); RightOffsetX = config.Bind("Rack.RightWall", "OffsetX", -1.000082f, "Local X offset of the right rack."); RightOffsetY = config.Bind("Rack.RightWall", "OffsetY", 0.8999996f, "Local Y offset of the right rack."); RightOffsetZ = config.Bind("Rack.RightWall", "OffsetZ", 1.999999f, "Local Z offset of the right rack."); RightRotationY = config.Bind("Rack.RightWall", "RotationY", -3.650784E-06f, "Extra Y rotation for the right rack."); EnableGrenadePlatform = config.Bind("Rack.GrenadePlatform", "Enable", true, "Build the grenade platform."); GrenadePlatformOffsetX = config.Bind("Rack.GrenadePlatform", "OffsetX", 2.149997f, "Local X offset of the grenade platform."); GrenadePlatformOffsetY = config.Bind("Rack.GrenadePlatform", "OffsetY", -0.6999996f, "Local Y offset of the grenade platform."); GrenadePlatformOffsetZ = config.Bind("Rack.GrenadePlatform", "OffsetZ", 1.499974f, "Local Z offset of the grenade platform."); GrenadePlatformRotationY = config.Bind("Rack.GrenadePlatform", "RotationY", 0f, "Extra Y rotation of the grenade platform."); GrenadePlatformSpacingX = config.Bind("Rack.GrenadePlatform", "SpacingX", 0.4f, "Horizontal distance between grenade platform cells."); GrenadePlatformSpacingZ = config.Bind("Rack.GrenadePlatform", "SpacingZ", 0.4000001f, "Depth distance between grenade platform cells."); GrenadePlatformSizeX = config.Bind("Rack.GrenadePlatform", "CellSizeX", 0.04999996f, "Width of each grenade platform marker."); GrenadePlatformSizeY = config.Bind("Rack.GrenadePlatform", "CellSizeY", 0.05f, "Height of each grenade platform marker."); GrenadePlatformSizeZ = config.Bind("Rack.GrenadePlatform", "CellSizeZ", 0.04999998f, "Depth of each grenade platform marker."); EnableDronePlatform = config.Bind("Rack.DronePlatform", "Enable", true, "Build the drone platform."); DronePlatformOffsetX = config.Bind("Rack.DronePlatform", "OffsetX", 2.000009f, "Local X offset of the drone platform."); DronePlatformOffsetY = config.Bind("Rack.DronePlatform", "OffsetY", -0.7000024f, "Local Y offset of the drone platform."); DronePlatformOffsetZ = config.Bind("Rack.DronePlatform", "OffsetZ", -1.400007f, "Local Z offset of the drone platform."); DronePlatformRotationY = config.Bind("Rack.DronePlatform", "RotationY", 0f, "Extra Y rotation of the drone platform."); DronePlatformSpacingX = config.Bind("Rack.DronePlatform", "SpacingX", 0.5000001f, "Horizontal distance between drone platform cells."); DronePlatformSpacingZ = config.Bind("Rack.DronePlatform", "SpacingZ", 0.5000006f, "Depth distance between drone platform cells."); DronePlatformSizeX = config.Bind("Rack.DronePlatform", "CellSizeX", 0.04999997f, "Width of each drone platform marker."); DronePlatformSizeY = config.Bind("Rack.DronePlatform", "CellSizeY", 0.04999999f, "Height of each drone platform marker."); DronePlatformSizeZ = config.Bind("Rack.DronePlatform", "CellSizeZ", 0.04999991f, "Depth of each drone platform marker."); EnableMinePlatform = config.Bind("Rack.MinePlatform", "Enable", true, "Build the mine/explosive-grenade platform."); MinePlatformOffsetX = config.Bind("Rack.MinePlatform", "OffsetX", 5.000046f, "Local X offset of the mine platform."); MinePlatformOffsetY = config.Bind("Rack.MinePlatform", "OffsetY", -1.589999f, "Local Y offset of the mine platform."); MinePlatformOffsetZ = config.Bind("Rack.MinePlatform", "OffsetZ", -1.600002f, "Local Z offset of the mine platform."); MinePlatformRotationY = config.Bind("Rack.MinePlatform", "RotationY", 0f, "Extra Y rotation of the mine platform."); MinePlatformSpacingX = config.Bind("Rack.MinePlatform", "SpacingX", 0.6499999f, "Horizontal distance between mine platform cells."); MinePlatformSpacingZ = config.Bind("Rack.MinePlatform", "SpacingZ", 0.6499999f, "Depth distance between mine platform cells."); MinePlatformSizeX = config.Bind("Rack.MinePlatform", "CellSizeX", 0.04999996f, "Width of each mine platform marker."); MinePlatformSizeY = config.Bind("Rack.MinePlatform", "CellSizeY", 0.05f, "Height of each mine platform marker."); MinePlatformSizeZ = config.Bind("Rack.MinePlatform", "CellSizeZ", 0.04999996f, "Depth of each mine platform marker."); try { config.Save(); Plugin.Log.LogInfo((object)"ItemRackMod configuration initialized and saved."); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not save ItemRackMod configuration: " + ex.Message)); } } private static void EnsurePlatformAssignments() { if (SlotAssignments == null) { return; } string text = SlotAssignments.Value ?? string.Empty; string[] collection = new string[30] { "DronePlatform:1:1=zero gravity drone", "DronePlatform:1:2=zero gravity orb", "DronePlatform:1:3=recharge drone", "DronePlatform:2:1=indestructible drone", "DronePlatform:2:2=roll drone", "DronePlatform:2:3=feather drone", "GrenadePlatform:1:1=granade", "GrenadePlatform:1:2=human granade", "GrenadePlatform:1:3=stun granade", "GrenadePlatform:1:4=shockwave mine", "GrenadePlatform:2:1=granade", "GrenadePlatform:2:2=human granade", "GrenadePlatform:2:3=stun granade", "GrenadePlatform:2:4=shockwave mine", "GrenadePlatform:3:1=granade", "GrenadePlatform:3:2=human granade", "GrenadePlatform:3:3=stun granade", "GrenadePlatform:3:4=shockwave mine", "MinePlatform:1:1=explosive mine", "MinePlatform:1:2=explosive mine", "MinePlatform:1:3=explosive mine", "MinePlatform:1:4=shockwave granade", "MinePlatform:1:5=shockwave granade", "MinePlatform:1:6=shockwave granade", "MinePlatform:2:1=trapzap", "MinePlatform:2:2=trapzap", "MinePlatform:2:3=trapzap", "MinePlatform:2:4=duct taped granade", "MinePlatform:2:5=duct taped granade", "MinePlatform:2:6=duct taped granade" }; List list = new List(); string[] array = text.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text2 in array) { string text3 = text2.Trim(); int num = text3.IndexOf('='); if (num > 0) { string text4 = text3.Substring(0, num).Trim(); if (!text4.StartsWith("DronePlatform:", StringComparison.OrdinalIgnoreCase) && !text4.StartsWith("GrenadePlatform:", StringComparison.OrdinalIgnoreCase) && !text4.StartsWith("MinePlatform:", StringComparison.OrdinalIgnoreCase)) { list.Add(text3); } } } list.AddRange(collection); SlotAssignments.Value = string.Join(",", list.ToArray()); Plugin.Log.LogInfo((object)"Platform item assignments migrated to the exact item names supplied by the user."); } public static string MakeSlotKey(string wall, int row, int column) { return $"{wall}:{row}:{column}"; } public static string MakePlatformSlotKey(string platformName, int row, int column) { return $"{platformName}:{row}:{column}"; } public static List ParseSlotAssignments() { List list = new List(); string text = SlotAssignments?.Value ?? string.Empty; if (string.IsNullOrWhiteSpace(text)) { return list; } string[] array = text.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); string[] array2 = array; foreach (string text2 in array2) { string text3 = text2.Trim(); int num = text3.IndexOf('='); if (num <= 0 || num >= text3.Length - 1) { continue; } string text4 = text3.Substring(0, num).Trim(); string text5 = text3.Substring(num + 1).Trim(); if (!string.IsNullOrWhiteSpace(text4) && !string.IsNullOrWhiteSpace(text5)) { string[] array3 = text4.Split(new char[1] { ':' }); if (array3.Length == 3 && int.TryParse(array3[1], out var result) && int.TryParse(array3[2], out var result2) && result >= 1 && result2 >= 1 && !string.IsNullOrWhiteSpace(array3[0])) { list.Add(new DefaultAssignment { SlotKey = MakeSlotKey(array3[0].Trim(), result, result2), ItemName = text5 }); } } } return list; } public static bool TryGetItemOrientation(string itemName, out Vector3 euler) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) euler = Vector3.zero; if (string.IsNullOrWhiteSpace(itemName)) { return false; } return CachedItemOrientations.TryGetValue(DefaultItemNameResolver.Normalize(itemName), out euler); } private static void RebuildItemOrientationCache() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) CachedItemOrientations.Clear(); foreach (KeyValuePair item in ParseItemOrientations()) { string text = DefaultItemNameResolver.Normalize(item.Key); if (!string.IsNullOrEmpty(text)) { CachedItemOrientations[text] = item.Value; } } } public static List> ParseItemOrientations() { //IL_0152: Unknown result type (might be due to invalid IL or missing references) List> list = new List>(); string text = ItemOrientations?.Value ?? string.Empty; if (string.IsNullOrWhiteSpace(text)) { return list; } string[] array = text.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); string[] array2 = array; foreach (string text2 in array2) { string text3 = text2.Trim(); int num = text3.IndexOf('='); if (num > 0 && num < text3.Length - 1) { string key = text3.Substring(0, num).Trim(); string[] array3 = text3.Substring(num + 1).Trim().Split(new char[1] { ',' }); if (array3.Length == 3 && float.TryParse(array3[0].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(array3[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && float.TryParse(array3[2].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result3)) { list.Add(new KeyValuePair(key, new Vector3(result, result2, result3))); } } } return list; } } [HarmonyPatch(typeof(TruckSafetySpawnPoint), "Awake")] internal static class TruckSafetySpawnPoint_Awake_Patch { private static void Postfix(TruckSafetySpawnPoint __instance) { if (!((Object)(object)__instance == (Object)null)) { ItemRackController component = ((Component)__instance).GetComponent(); if (!((Object)(object)component != (Object)null)) { component = ((Component)__instance).gameObject.AddComponent(); component.Init(((Component)__instance).transform); Plugin.Log.LogInfo((object)"Item racks attached inside the truck (anchored to TruckSafetySpawnPoint)."); } } } } [BepInPlugin("Item.Shelves.Platforms", "Item Shelves & Platforms", "1.4.3")] public class Plugin : BaseUnityPlugin { public const string Guid = "Item.Shelves.Platforms"; public const string Name = "Item Shelves & Platforms"; public const string Version = "1.4.3"; internal static ManualLogSource Log; private Harmony _harmony; private void Awake() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ModConfig.Init(((BaseUnityPlugin)this).Config); _harmony = new Harmony("Item.Shelves.Platforms"); _harmony.PatchAll(); SceneManager.sceneLoaded += OnSceneLoaded; Log.LogInfo((object)"Item Shelves & Platforms v1.4.3 loaded, patches applied."); } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { ItemRackController[] array = Object.FindObjectsOfType(); if (array == null) { return; } ItemRackController[] array2 = array; foreach (ItemRackController itemRackController in array2) { if ((Object)(object)itemRackController != (Object)null) { itemRackController.ResetForNewScene(); } } } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } }