Decompiled source of BetterShop v1.1.0

plugins/BetterShop/BetterShop.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using Alexandria.DungeonAPI;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BetterShop.Patches;
using Dungeonator;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("BetterShop")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+2bbcbff1c6ec136a99f87080001e079bac414d57")]
[assembly: AssemblyProduct("BetterShop")]
[assembly: AssemblyTitle("BetterShop")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace BetterShop
{
	[BepInPlugin("com.bettershop.etg", "BetterShop", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string PLUGIN_GUID = "com.bettershop.etg";

		public const string PLUGIN_NAME = "BetterShop";

		public const string PLUGIN_VERSION = "1.0.0";

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		internal static ConfigEntry<int> MinGuns;

		internal static ConfigEntry<int> MinItems;

		internal static ConfigEntry<int> ExtraNpcCount;

		internal static ConfigEntry<bool> BulletHellShopEnabled;

		private void Awake()
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Expected O, but got Unknown
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			MinGuns = ((BaseUnityPlugin)this).Config.Bind<int>("商店保底", "MinGuns", 1, "商店中至少包含的枪械数量");
			MinItems = ((BaseUnityPlugin)this).Config.Bind<int>("商店保底", "MinItems", 1, "商店中至少包含的道具数量");
			ExtraNpcCount = ((BaseUnityPlugin)this).Config.Bind<int>("额外NPC", "Count", 1, new ConfigDescription("每层额外生成的 NPC 数量(0=禁用,1-3)", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 3), new object[0]));
			BulletHellShopEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("枪弹地狱", "ShopEnabled", true, "是否在枪弹地狱(第六层)生成商人");
			new Harmony("com.bettershop.etg").PatchAll();
			HellShopGenerator.Init();
			ExtraNpcInjector.Init();
			Log.LogInfo((object)"BetterShop v1.0.0 已加载!Alexandria 依赖注入成功!");
		}
	}
}
namespace BetterShop.Patches
{
	public static class ExtraNpcInjector
	{
		private struct NpcCandidate
		{
			public ProceduralFlowModifierData Modifier;

			public string SourceName;
		}

		private static readonly string[] AnnotationBlacklist = new string[11]
		{
			"shrine", "black_market", "elevator", "exit", "entrance", "boss", "crest", "fireplace", "muncher", "prayer",
			"secret"
		};

		public static void Init()
		{
			DungeonHooks.OnPreDungeonGeneration += OnPreDungeonGen;
		}

		private static List<NpcCandidate> CollectAllNpcRooms(DungeonFlow flow)
		{
			HashSet<string> seenKeys = new HashSet<string>();
			List<NpcCandidate> result = new List<NpcCandidate>();
			CollectFromNamedSource(StaticInjections.NPC_injections, "NPC_injections", seenKeys, result, requireSpecialCategory: false);
			CollectFromNamedSource(StaticInjections.Fallback_Subshop_Injections, "Fallback_Subshop(Vampire/GunMuncher)", seenKeys, result, requireSpecialCategory: false);
			CollectFromNamedSource(StaticReferences.subShopTable, "SubShopTable(OldRed/Cursula/Flynt/Trorc/Goopton)", seenKeys, result, requireSpecialCategory: false);
			if (GameManager.Instance?.GlobalInjectionData?.entries != null)
			{
				foreach (MetaInjectionDataEntry entry in GameManager.Instance.GlobalInjectionData.entries)
				{
					if (entry?.injectionData?.InjectionData != null)
					{
						CollectFromNamedSource(entry.injectionData, "GlobalInjection/" + (((Object)entry.injectionData).name ?? "?"), seenKeys, result, requireSpecialCategory: true);
					}
				}
			}
			if (flow.sharedInjectionData != null)
			{
				foreach (SharedInjectionData sharedInjectionDatum in flow.sharedInjectionData)
				{
					if (sharedInjectionDatum?.InjectionData == null)
					{
						continue;
					}
					CollectFromNamedSource(sharedInjectionDatum, "FlowShared/" + (((Object)sharedInjectionDatum).name ?? "?"), seenKeys, result, requireSpecialCategory: true);
					if (sharedInjectionDatum.AttachedInjectionData == null)
					{
						continue;
					}
					foreach (SharedInjectionData attachedInjectionDatum in sharedInjectionDatum.AttachedInjectionData)
					{
						if (attachedInjectionDatum?.InjectionData != null)
						{
							CollectFromNamedSource(attachedInjectionDatum, "FlowShared/attached", seenKeys, result, requireSpecialCategory: true);
						}
					}
				}
			}
			return result;
		}

		private static void CollectFromNamedSource(SharedInjectionData data, string sourceName, HashSet<string> seenKeys, List<NpcCandidate> result, bool requireSpecialCategory)
		{
			if ((Object)(object)data == (Object)null || data.InjectionData == null)
			{
				return;
			}
			Plugin.Log.LogDebug((object)$"  [来源:{sourceName}] 共 {data.InjectionData.Count} 条");
			foreach (ProceduralFlowModifierData injectionDatum in data.InjectionData)
			{
				string modifierKey = GetModifierKey(injectionDatum);
				if (string.IsNullOrEmpty(modifierKey) || seenKeys.Contains(modifierKey))
				{
					continue;
				}
				if (!IsValidNpc(injectionDatum, requireSpecialCategory))
				{
					Plugin.Log.LogDebug((object)("    - 跳过: " + modifierKey + " (不满足条件, 来源: " + sourceName + ")"));
					continue;
				}
				string lowerAnnotation = (injectionDatum.annotation ?? "").ToLower();
				if (!IsAnnotationBlacklisted(modifierKey.ToLower(), lowerAnnotation))
				{
					seenKeys.Add(modifierKey);
					result.Add(new NpcCandidate
					{
						Modifier = injectionDatum,
						SourceName = sourceName
					});
					Plugin.Log.LogDebug((object)("    + 收集: " + modifierKey + " (来源: " + sourceName + ")"));
				}
			}
		}

		private static string GetModifierKey(ProceduralFlowModifierData mod)
		{
			if (!string.IsNullOrEmpty(mod.annotation))
			{
				if (mod.annotation.StartsWith("CHALLENGE - "))
				{
					return "CHALLENGE";
				}
				return mod.annotation;
			}
			if ((Object)(object)mod.exactRoom != (Object)null && !string.IsNullOrEmpty(((Object)mod.exactRoom).name))
			{
				return ((Object)mod.exactRoom).name;
			}
			if (mod.roomTable?.includedRooms?.elements != null)
			{
				foreach (WeightedRoom element in mod.roomTable.includedRooms.elements)
				{
					if ((Object)(object)element?.room != (Object)null && !string.IsNullOrEmpty(((Object)element.room).name))
					{
						return "table:" + ((Object)element.room).name;
					}
				}
			}
			return null;
		}

		private static bool IsValidNpc(ProceduralFlowModifierData mod, bool requireSpecialCategory)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Invalid comparison between Unknown and I4
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Invalid comparison between Unknown and I4
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Invalid comparison between Unknown and I4
			if ((Object)(object)mod.exactRoom != (Object)null)
			{
				if (requireSpecialCategory && (int)mod.exactRoom.category != 5)
				{
					return false;
				}
				return true;
			}
			if (mod.roomTable?.includedRooms?.elements != null && mod.roomTable.includedRooms.elements.Count > 0)
			{
				if (requireSpecialCategory)
				{
					foreach (WeightedRoom element in mod.roomTable.includedRooms.elements)
					{
						if ((Object)(object)element?.room != (Object)null && (int)element.room.category == 5)
						{
							return true;
						}
					}
					if (mod.roomTable.includedRoomTables != null)
					{
						foreach (GenericRoomTable includedRoomTable in mod.roomTable.includedRoomTables)
						{
							if (includedRoomTable?.includedRooms?.elements == null)
							{
								continue;
							}
							foreach (WeightedRoom element2 in includedRoomTable.includedRooms.elements)
							{
								if ((Object)(object)element2?.room != (Object)null && (int)element2.room.category == 5)
								{
									return true;
								}
							}
						}
					}
					return false;
				}
				return true;
			}
			if (mod.roomTable?.includedRoomTables != null)
			{
				foreach (GenericRoomTable includedRoomTable2 in mod.roomTable.includedRoomTables)
				{
					if (includedRoomTable2?.includedRooms?.elements != null && includedRoomTable2.includedRooms.elements.Count > 0)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool IsAnnotationBlacklisted(string lowerKey, string lowerAnnotation)
		{
			for (int i = 0; i < AnnotationBlacklist.Length; i++)
			{
				string value = AnnotationBlacklist[i];
				if (lowerKey.Contains(value) || lowerAnnotation.Contains(value))
				{
					return true;
				}
			}
			return false;
		}

		private static void OnPreDungeonGen(LoopDungeonGenerator generator, Dungeon dungeon, DungeonFlow flow, int dungeonSeed)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Invalid comparison between Unknown and I4
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: 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_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Expected O, but got Unknown
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			int value = Plugin.ExtraNpcCount.Value;
			if (value <= 0)
			{
				return;
			}
			if ((int)dungeon.tileIndices.tilesetId == 64)
			{
				Plugin.Log.LogInfo((object)"[BetterShop] 裂隙层已排除,不注入额外 NPC。");
			}
			else
			{
				if (((Object)flow).name == "Foyer Flow" || GameManager.IsReturningToFoyerWithPlayer)
				{
					return;
				}
				Plugin.Log.LogInfo((object)"[BetterShop] 正在从所有注入源收集 NPC...");
				List<NpcCandidate> list = CollectAllNpcRooms(flow);
				if (list.Count == 0)
				{
					Plugin.Log.LogWarning((object)"[BetterShop] 未找到任何有效的 NPC 房间!");
					return;
				}
				Plugin.Log.LogInfo((object)$"[BetterShop] 已收集 {list.Count} 个 NPC 候选:");
				for (int i = 0; i < list.Count; i++)
				{
					string arg = GetModifierKey(list[i].Modifier) ?? "?";
					string sourceName = list[i].SourceName;
					Plugin.Log.LogInfo((object)$"   [{i}] {arg}  ({sourceName})");
				}
				int num = Mathf.Min(value, list.Count);
				List<NpcCandidate> list2 = new List<NpcCandidate>(list);
				for (int j = 0; j < num; j++)
				{
					int index = Random.Range(0, list2.Count);
					ProceduralFlowModifierData modifier = list2[index].Modifier;
					list2.RemoveAt(index);
					string text = GetModifierKey(modifier) ?? "unknown";
					ProceduralFlowModifierData item = new ProceduralFlowModifierData
					{
						annotation = "BetterShop Extra NPC: " + text,
						DEBUG_FORCE_SPAWN = false,
						OncePerRun = false,
						placementRules = new List<FlowModifierPlacementType>
						{
							(FlowModifierPlacementType)1,
							(FlowModifierPlacementType)3
						},
						roomTable = modifier.roomTable,
						exactRoom = modifier.exactRoom,
						exactSecondaryRoom = modifier.exactSecondaryRoom,
						framedCombatNodes = 0,
						IsWarpWing = false,
						RequiresMasteryToken = false,
						chanceToLock = 0f,
						selectionWeight = 300f,
						chanceToSpawn = 1f,
						RequiredValidPlaceable = modifier.RequiredValidPlaceable,
						prerequisites = (DungeonPrerequisite[])(object)new DungeonPrerequisite[0],
						CanBeForcedSecret = false,
						RandomNodeChildMinDistanceFromEntrance = 0
					};
					SharedInjectionData val = ScriptableObject.CreateInstance<SharedInjectionData>();
					((Object)val).name = "BetterShop_ExtraNPC_" + text;
					val.UseInvalidWeightAsNoInjection = true;
					val.PreventInjectionOfFailedPrerequisites = false;
					val.IsNPCCell = true;
					val.IgnoreUnmetPrerequisiteEntries = false;
					val.OnlyOne = false;
					val.ChanceToSpawnOne = 1f;
					val.AttachedInjectionData = new List<SharedInjectionData>();
					val.InjectionData = new List<ProceduralFlowModifierData> { item };
					if (flow.sharedInjectionData == null)
					{
						flow.sharedInjectionData = new List<SharedInjectionData>();
					}
					flow.sharedInjectionData.Add(val);
					Plugin.Log.LogInfo((object)$"[BetterShop] 额外 NPC 注入成功:{text} (层: {dungeon.tileIndices.tilesetId})");
				}
				Plugin.Log.LogInfo((object)$"[BetterShop] 共注入 {num} 个额外 NPC。");
			}
		}
	}
	public static class HellShopGenerator
	{
		public static void Init()
		{
			DungeonHooks.OnPreDungeonGeneration += InjectHellShopViaInjection;
		}

		private static void InjectHellShopViaInjection(LoopDungeonGenerator generator, Dungeon dungeon, DungeonFlow flow, int dungeonSeed)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Invalid comparison between Unknown and I4
			//IL_0310: Unknown result type (might be due to invalid IL or missing references)
			//IL_0315: Unknown result type (might be due to invalid IL or missing references)
			//IL_0320: Unknown result type (might be due to invalid IL or missing references)
			//IL_0327: Unknown result type (might be due to invalid IL or missing references)
			//IL_032e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: Unknown result type (might be due to invalid IL or missing references)
			//IL_034e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0355: Unknown result type (might be due to invalid IL or missing references)
			//IL_035c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0363: Unknown result type (might be due to invalid IL or missing references)
			//IL_036a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0371: Unknown result type (might be due to invalid IL or missing references)
			//IL_037c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0387: Unknown result type (might be due to invalid IL or missing references)
			//IL_0392: Unknown result type (might be due to invalid IL or missing references)
			//IL_0399: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b4: Expected O, but got Unknown
			if (!Plugin.BulletHellShopEnabled.Value || (int)dungeon.tileIndices.tilesetId != 128)
			{
				return;
			}
			Plugin.Log.LogInfo((object)"[BetterShop] 正在适配注入 Bello 商店至第六层...");
			Dungeon orLoadByName = DungeonDatabase.GetOrLoadByName("Base_Castle");
			PrototypeDungeonRoom val = null;
			string text = null;
			foreach (DungeonFlow flow2 in orLoadByName.PatternSettings.flows)
			{
				if (flow2.sharedInjectionData != null)
				{
					foreach (SharedInjectionData sharedInjectionDatum in flow2.sharedInjectionData)
					{
						if ((Object)(object)sharedInjectionDatum == (Object)null || sharedInjectionDatum.InjectionData == null)
						{
							continue;
						}
						foreach (ProceduralFlowModifierData injectionDatum in sharedInjectionDatum.InjectionData)
						{
							if ((Object)(object)injectionDatum.exactRoom != (Object)null && ((Object)injectionDatum.exactRoom).name.ToLower().Contains("shop"))
							{
								val = injectionDatum.exactRoom;
								text = "SharedInjectionData";
								break;
							}
						}
						if ((Object)(object)val != (Object)null)
						{
							break;
						}
					}
				}
				if ((Object)(object)val != (Object)null)
				{
					break;
				}
				foreach (DungeonFlowNode allNode in flow2.AllNodes)
				{
					if ((Object)(object)allNode.overrideExactRoom != (Object)null && ((Object)allNode.overrideExactRoom).name.ToLower().Contains("shop"))
					{
						val = allNode.overrideExactRoom;
						text = "FlowNode.overrideExactRoom";
						break;
					}
				}
				if ((Object)(object)val != (Object)null)
				{
					break;
				}
				foreach (DungeonFlowNode allNode2 in flow2.AllNodes)
				{
					if ((Object)(object)allNode2.overrideRoomTable != (Object)null && allNode2.overrideRoomTable.includedRooms != null)
					{
						foreach (WeightedRoom element in allNode2.overrideRoomTable.includedRooms.elements)
						{
							if ((Object)(object)element.room != (Object)null && ((Object)element.room).name.ToLower().Contains("shop"))
							{
								val = element.room;
								text = "FlowNode.overrideRoomTable";
								break;
							}
						}
					}
					if ((Object)(object)val != (Object)null)
					{
						break;
					}
				}
				if ((Object)(object)val != (Object)null)
				{
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogError((object)"[BetterShop] 无法在 Castle 资源中找到商店模板!(已搜索 SharedInjectionData / FlowNode / RoomTable)");
				return;
			}
			Plugin.Log.LogInfo((object)("[BetterShop] 找到商店模板: " + ((Object)val).name + " (来源: " + text + ")"));
			ProceduralFlowModifierData item = new ProceduralFlowModifierData
			{
				annotation = "Bello Shop Injector",
				DEBUG_FORCE_SPAWN = false,
				OncePerRun = false,
				placementRules = new List<FlowModifierPlacementType>
				{
					(FlowModifierPlacementType)1,
					(FlowModifierPlacementType)3
				},
				roomTable = null,
				exactRoom = val,
				exactSecondaryRoom = null,
				framedCombatNodes = 0,
				IsWarpWing = false,
				RequiresMasteryToken = false,
				chanceToLock = 0f,
				selectionWeight = 10000f,
				chanceToSpawn = 1f,
				RequiredValidPlaceable = null,
				prerequisites = (DungeonPrerequisite[])(object)new DungeonPrerequisite[0],
				CanBeForcedSecret = false,
				RandomNodeChildMinDistanceFromEntrance = 0
			};
			SharedInjectionData val2 = ScriptableObject.CreateInstance<SharedInjectionData>();
			((Object)val2).name = "BetterShop_Hell_Injection";
			val2.UseInvalidWeightAsNoInjection = true;
			val2.PreventInjectionOfFailedPrerequisites = false;
			val2.IsNPCCell = false;
			val2.IgnoreUnmetPrerequisiteEntries = false;
			val2.OnlyOne = false;
			val2.ChanceToSpawnOne = 1f;
			val2.AttachedInjectionData = new List<SharedInjectionData>();
			val2.InjectionData = new List<ProceduralFlowModifierData> { item };
			if (flow.sharedInjectionData == null)
			{
				flow.sharedInjectionData = new List<SharedInjectionData>();
			}
			flow.sharedInjectionData.Add(val2);
			Plugin.Log.LogInfo((object)"[BetterShop] 注入成功:商店已加入第六层生成队列。");
		}
	}
	[HarmonyPatch(typeof(BaseShopController), "DoSetup")]
	public class ShopGuaranteePatch
	{
		private static bool IsRealItem(PickupObject item)
		{
			if ((Object)(object)item == (Object)null || item is Gun)
			{
				return false;
			}
			if (item is HealthPickup || item is AmmoPickup || item is KeyBulletPickup || item is SilencerItem)
			{
				return false;
			}
			if (item.PickupObjectId == 565 || item.PickupObjectId == 137 || item.PickupObjectId == 316)
			{
				return false;
			}
			if (!(item is PlayerItem))
			{
				return item is PassiveItem;
			}
			return true;
		}

		[HarmonyPostfix]
		public static void Postfix(BaseShopController __instance, ref List<ShopItemController> ___m_itemControllers, ref List<GameObject> ___m_shopItems)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if ((int)__instance.baseShopType != 0)
			{
				return;
			}
			if (GameStatsManager.Instance != null && GameStatsManager.Instance.IsRainbowRun)
			{
				Plugin.Log.LogInfo((object)"[BetterShop] 彩虹模式,保底已禁用。");
				return;
			}
			int value = Plugin.MinGuns.Value;
			int value2 = Plugin.MinItems.Value;
			if ((value <= 0 && value2 <= 0) || ___m_itemControllers == null || ___m_itemControllers.Count == 0)
			{
				return;
			}
			int num = 0;
			int num2 = 0;
			int num3 = ((__instance.spawnPositions != null) ? __instance.spawnPositions.Length : 0);
			Plugin.Log.LogInfo((object)"==================================================");
			Plugin.Log.LogInfo((object)"[BetterShop] 商店生成完毕,扫描台面物品...");
			for (int i = 0; i < ___m_itemControllers.Count; i++)
			{
				ShopItemController val = ___m_itemControllers[i];
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val.item == (Object)null))
				{
					string text = "消耗品/杂物";
					if (val.item is Gun)
					{
						num++;
						text = "【枪械】";
					}
					else if (IsRealItem(val.item))
					{
						num2++;
						text = "【道具】";
					}
					Plugin.Log.LogInfo((object)$"  [{i}] ID:{val.item.PickupObjectId,-4} {text,-8} {val.item.EncounterNameOrDisplayName}");
				}
			}
			Plugin.Log.LogInfo((object)$"[BetterShop] 枪:{num}/{value}  道具:{num2}/{value2}");
			bool flag = num < value;
			bool flag2 = num2 < value2;
			if (!flag && !flag2)
			{
				Plugin.Log.LogInfo((object)"[BetterShop] 已达标!");
				Plugin.Log.LogInfo((object)"==================================================\n");
				return;
			}
			Transform[] spawnPositionsGroup = __instance.spawnPositionsGroup2;
			if (spawnPositionsGroup == null || spawnPositionsGroup.Length == 0)
			{
				Plugin.Log.LogWarning((object)"[BetterShop] 无 Group2 位置,无法补齐。");
				Plugin.Log.LogInfo((object)"==================================================\n");
				return;
			}
			List<int> list = new List<int>();
			List<int> list2 = new List<int>();
			HashSet<int> hashSet = new HashSet<int>();
			for (int j = num3; j < ___m_itemControllers.Count; j++)
			{
				ShopItemController val2 = ___m_itemControllers[j];
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				for (int k = 0; k < spawnPositionsGroup.Length; k++)
				{
					if ((Object)(object)((BraveBehaviour)val2).transform.parent == (Object)(object)spawnPositionsGroup[k])
					{
						hashSet.Add(k);
						if ((Object)(object)val2.item != (Object)null && !(val2.item is Gun) && !IsRealItem(val2.item))
						{
							list2.Add(j);
						}
						break;
					}
				}
			}
			for (int l = 0; l < spawnPositionsGroup.Length; l++)
			{
				if (!hashSet.Contains(l))
				{
					list.Add(l);
				}
			}
			Plugin.Log.LogInfo((object)$"[BetterShop] Group2 空位:{list.Count}  消耗品位:{list2.Count}");
			PlayerController primaryPlayer = GameManager.Instance.PrimaryPlayer;
			if (flag)
			{
				if (list.Count > 0)
				{
					int num4 = list[0];
					list.RemoveAt(0);
					GameObject rewardObjectShopStyle = GameManager.Instance.RewardManager.GetRewardObjectShopStyle(primaryPlayer, true, false, ___m_shopItems);
					if ((Object)(object)rewardObjectShopStyle != (Object)null)
					{
						PickupObject component = rewardObjectShopStyle.GetComponent<PickupObject>();
						if ((Object)(object)component != (Object)null)
						{
							SpawnShopItem(component, spawnPositionsGroup[num4], __instance, ___m_itemControllers, ___m_shopItems);
							num++;
							Plugin.Log.LogInfo((object)$"[BetterShop] >>> 空位补枪: [{component.EncounterNameOrDisplayName}] (ID:{component.PickupObjectId})");
						}
					}
				}
				else if (list2.Count > 0)
				{
					int index = list2[0];
					list2.RemoveAt(0);
					GameObject rewardObjectShopStyle2 = GameManager.Instance.RewardManager.GetRewardObjectShopStyle(primaryPlayer, true, false, ___m_shopItems);
					if ((Object)(object)rewardObjectShopStyle2 != (Object)null)
					{
						PickupObject component2 = rewardObjectShopStyle2.GetComponent<PickupObject>();
						if ((Object)(object)component2 != (Object)null)
						{
							PickupObject item = ___m_itemControllers[index].item;
							string text2 = ((item != null) ? item.EncounterNameOrDisplayName : null) ?? "?";
							___m_itemControllers[index].Initialize(component2, __instance);
							num++;
							Plugin.Log.LogInfo((object)("[BetterShop] >>> 替换补枪: [" + text2 + "] -> [" + component2.EncounterNameOrDisplayName + "]"));
						}
					}
				}
			}
			if (num2 < value2)
			{
				if (list.Count > 0)
				{
					int num5 = list[0];
					list.RemoveAt(0);
					PickupObject guaranteedItem = GetGuaranteedItem(__instance, ___m_shopItems);
					if ((Object)(object)guaranteedItem != (Object)null)
					{
						SpawnShopItem(guaranteedItem, spawnPositionsGroup[num5], __instance, ___m_itemControllers, ___m_shopItems);
						num2++;
						Plugin.Log.LogInfo((object)$"[BetterShop] >>> 空位补道具: [{guaranteedItem.EncounterNameOrDisplayName}] (ID:{guaranteedItem.PickupObjectId})");
					}
				}
				else if (list2.Count > 0)
				{
					int index2 = list2[0];
					list2.RemoveAt(0);
					PickupObject guaranteedItem2 = GetGuaranteedItem(__instance, ___m_shopItems);
					if ((Object)(object)guaranteedItem2 != (Object)null)
					{
						PickupObject item2 = ___m_itemControllers[index2].item;
						string text3 = ((item2 != null) ? item2.EncounterNameOrDisplayName : null) ?? "?";
						___m_itemControllers[index2].Initialize(guaranteedItem2, __instance);
						num2++;
						Plugin.Log.LogInfo((object)("[BetterShop] >>> 替换补道具: [" + text3 + "] -> [" + guaranteedItem2.EncounterNameOrDisplayName + "]"));
					}
				}
			}
			Plugin.Log.LogInfo((object)$"[BetterShop] 最终: 枪:{num}  道具:{num2}");
			Plugin.Log.LogInfo((object)"==================================================\n");
		}

		private static void SpawnShopItem(PickupObject pickup, Transform spawnPos, BaseShopController shop, List<ShopItemController> controllers, List<GameObject> shopItems)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Shop guaranteed item");
			val.transform.parent = spawnPos;
			val.transform.localPosition = Vector3.zero;
			EncounterTrackable component = ((Component)pickup).GetComponent<EncounterTrackable>();
			if ((Object)(object)component != (Object)null)
			{
				GameManager.Instance.ExtantShopTrackableGuids.Add(component.EncounterGuid);
			}
			ShopItemController val2 = val.AddComponent<ShopItemController>();
			if (((Object)spawnPos).name.Contains("SIDE") || ((Object)spawnPos).name.Contains("EAST"))
			{
				val2.itemFacing = (Direction)2;
			}
			else if (((Object)spawnPos).name.Contains("WEST"))
			{
				val2.itemFacing = (Direction)6;
			}
			else if (((Object)spawnPos).name.Contains("NORTH"))
			{
				val2.itemFacing = (Direction)0;
			}
			RoomHandler absoluteParentRoom = ((DungeonPlaceableBehaviour)shop).GetAbsoluteParentRoom();
			if (absoluteParentRoom != null && !absoluteParentRoom.IsRegistered((IPlayerInteractable)(object)val2))
			{
				absoluteParentRoom.RegisterInteractable((IPlayerInteractable)(object)val2);
			}
			val2.Initialize(pickup, shop);
			controllers.Add(val2);
			shopItems.Add(((Component)pickup).gameObject);
		}

		private static PickupObject GetGuaranteedItem(BaseShopController shop, List<GameObject> exclude)
		{
			PlayerController primaryPlayer = GameManager.Instance.PrimaryPlayer;
			for (int i = 0; i < 10; i++)
			{
				GameObject rewardObjectShopStyle = GameManager.Instance.RewardManager.GetRewardObjectShopStyle(primaryPlayer, false, false, exclude);
				if (!((Object)(object)rewardObjectShopStyle == (Object)null))
				{
					PickupObject component = rewardObjectShopStyle.GetComponent<PickupObject>();
					if ((Object)(object)component != (Object)null && IsRealItem(component))
					{
						return component;
					}
				}
			}
			GameObject val = shop.shopItems.SelectByWeightWithoutDuplicatesFullPrereqs(exclude, (Func<GameObject, float, float>)null, GameManager.Instance.IsSeeded);
			if ((Object)(object)val != (Object)null)
			{
				PickupObject component2 = val.GetComponent<PickupObject>();
				if ((Object)(object)component2 != (Object)null && IsRealItem(component2))
				{
					return component2;
				}
			}
			Plugin.Log.LogWarning((object)"[BetterShop] 无法找到合适的道具进行补齐。");
			return null;
		}
	}
}