using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using R2API;
using RoR2;
using UnityEngine;
using UnityEngine.Networking;
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: AssemblyTitle("ShareChest")]
[assembly: AssemblyDescription("共享宝箱 - Risk of Rain 2 模组")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Muskmelovon")]
[assembly: AssemblyProduct("ShareChest")]
[assembly: AssemblyCopyright("Copyright © Muskmelovon 2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("f2eff138-24ee-4741-88c1-c6ff8bf1d179")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace ShareChest
{
public abstract class ArtifactBase
{
public ArtifactDef ArtifactDef;
public abstract string ArtifactName { get; }
public abstract string ArtifactLangTokenName { get; }
public abstract string ArtifactDescription { get; }
public abstract Sprite ArtifactEnabledIcon { get; }
public abstract Sprite ArtifactDisabledIcon { get; }
public virtual string DisplayName => ArtifactName;
public bool ArtifactEnabled
{
get
{
RunArtifactManager instance = RunArtifactManager.instance;
return instance != null && instance.IsArtifactEnabled(ArtifactDef);
}
}
public abstract void Init(ConfigFile config);
protected void CreateLang()
{
LanguageAPI.Add("ARTIFACT_" + ArtifactLangTokenName + "_NAME", DisplayName);
LanguageAPI.Add("ARTIFACT_" + ArtifactLangTokenName + "_DESCRIPTION", ArtifactDescription);
}
protected bool CreateArtifact()
{
ArtifactDef = ScriptableObject.CreateInstance<ArtifactDef>();
ArtifactDef.cachedName = "ARTIFACT_" + ArtifactLangTokenName;
ArtifactDef.nameToken = "ARTIFACT_" + ArtifactLangTokenName + "_NAME";
ArtifactDef.descriptionToken = "ARTIFACT_" + ArtifactLangTokenName + "_DESCRIPTION";
ArtifactDef.smallIconSelectedSprite = ArtifactEnabledIcon;
ArtifactDef.smallIconDeselectedSprite = ArtifactDisabledIcon;
bool flag = ContentAddition.AddArtifactDef(ArtifactDef);
if (!flag)
{
ShareChestPlugin.LogError("神器 " + ArtifactName + " 添加失败!可能图标为null或重复。");
}
return flag;
}
public abstract void Hooks();
}
internal class ArtifactOfEquilibrium : ArtifactBase
{
public override string ArtifactName => "Artifact of Equilibrium";
public override string ArtifactLangTokenName => "EQUILIBRIUM";
public override string DisplayName => "Artifact of Equilibrium - 均衡神器";
public override string ArtifactDescription => "开启后,宝箱会掉落多倍物品(根据玩家数量动态调整或固定倍率,需前往配置文件修改配置)。\n启用此神器以激活共享宝箱Mod的多倍掉落。\n\nOnce activated, the treasure chest will drop items in multiple times (the multiplier is dynamically adjusted according to the number of players or can be set as a fixed rate. The configuration needs to be modified in the configuration file). \nEnable this artifact to activate the multiple-dropping feature of the Shared Treasure Chest Mod.";
public override Sprite ArtifactEnabledIcon => GetIcon("ArtifactOfEquilibrium_On");
public override Sprite ArtifactDisabledIcon => GetIcon("ArtifactOfEquilibrium_Off");
private Sprite GetIcon(string iconName)
{
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Expected O, but got Unknown
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_006c: Unknown result type (might be due to invalid IL or missing references)
//IL_0071: 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_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_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_0093: 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_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00da: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)ShareChestPlugin.MainAssets != (Object)null)
{
Sprite val = ShareChestPlugin.MainAssets.LoadAsset<Sprite>(iconName);
if ((Object)(object)val != (Object)null)
{
return val;
}
ShareChestPlugin.LogWarning("未找到图标 " + iconName + ",将使用默认占位图标");
}
else
{
ShareChestPlugin.LogWarning("AssetBundle 未加载,使用默认占位图标");
}
Texture2D val2 = new Texture2D(2, 2);
val2.SetPixels32((Color32[])(object)new Color32[4]
{
Color32.op_Implicit(Color.clear),
Color32.op_Implicit(Color.clear),
Color32.op_Implicit(Color.clear),
Color32.op_Implicit(Color.clear)
});
val2.Apply();
return Sprite.Create(val2, new Rect(0f, 0f, 2f, 2f), new Vector2(0.5f, 0.5f));
}
public override void Init(ConfigFile config)
{
CreateLang();
if (CreateArtifact())
{
ShareChestPlugin.LogInfo("神器 " + ArtifactName + " 已成功注册到游戏。");
}
else
{
ShareChestPlugin.LogError("神器 " + ArtifactName + " 注册失败。");
}
Hooks();
}
public override void Hooks()
{
Run.onRunStartGlobal += OnRunStart;
}
private void OnRunStart(Run run)
{
if (NetworkServer.active)
{
ShareChestPlugin.IsArtifactEnabled = base.ArtifactEnabled;
ShareChestPlugin.LogInfo("神器均衡宝箱状态: " + (ShareChestPlugin.IsArtifactEnabled ? "启用" : "禁用"));
}
}
}
[BepInPlugin("com.Muskmelovon.ShareChest", "共享宝箱", "1.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class ShareChestPlugin : BaseUnityPlugin
{
public const string PluginGUID = "com.Muskmelovon.ShareChest";
public const string PluginName = "共享宝箱";
public const string PluginVersion = "1.0.0";
private static ManualLogSource Log;
private static Harmony harmony;
public static ConfigEntry<bool> ModEnabled;
public static ConfigEntry<bool> EnableDynamicMultiplier;
public static ConfigEntry<int> FixedMultiplier;
public static ConfigEntry<bool> EnableDebugLogs;
public static ConfigEntry<string> AffectedChestTypes;
public static ConfigEntry<float> DropDistanceClamp;
private static readonly string ChestListSeparator = ",";
private static HashSet<string> affectedChestTypeSet = new HashSet<string>();
public static AssetBundle MainAssets;
private static List<ArtifactBase> artifacts = new List<ArtifactBase>();
public static bool IsArtifactEnabled = false;
public static bool IsInitialized { get; private set; } = false;
public void Awake()
{
Log = ((BaseUnityPlugin)this).Logger;
try
{
Log.LogInfo((object)"========== 共享宝箱 v1.0.0 初始化开始 ==========");
LoadAssetBundle();
InitializePlayerCountManager();
InitializeConfiguration();
InitializeArtifacts();
InitializeHarmonyPatches();
IsInitialized = true;
Log.LogInfo((object)"插件初始化成功!");
Log.LogInfo((object)$"当前配置:插件总开关={ModEnabled.Value}, 动态倍率={EnableDynamicMultiplier.Value}");
Log.LogInfo((object)$"掉落距离设置:{DropDistanceClamp.Value}(原版为6)");
Log.LogInfo((object)("应用倍率的宝箱类型:" + ((affectedChestTypeSet.Count > 0) ? string.Join(", ", affectedChestTypeSet) : "所有宝箱")));
Log.LogInfo((object)"配置位置:BepInEx/config/com.Muskmelovon.ShareChest.cfg");
Log.LogInfo((object)"调试命令:按 F5 显示调试信息,按 F6 强制重新计算玩家数量");
Log.LogInfo((object)"==================================================");
}
catch (Exception ex)
{
Log.LogError((object)"插件初始化失败!");
Log.LogError((object)("错误信息:" + ex.Message));
Log.LogError((object)("堆栈跟踪:" + ex.StackTrace));
if (ex.InnerException != null)
{
Log.LogError((object)("内部异常:" + ex.InnerException.Message));
}
try
{
Harmony obj = harmony;
if (obj != null)
{
obj.UnpatchSelf();
}
}
catch
{
}
throw;
}
}
private void LoadAssetBundle()
{
string[] manifestResourceNames = Assembly.GetExecutingAssembly().GetManifestResourceNames();
string text = manifestResourceNames.FirstOrDefault((string r) => r.EndsWith(".assets", StringComparison.OrdinalIgnoreCase));
if (text == null)
{
Log.LogWarning((object)"未找到任何 .assets 嵌入资源,神器图标将使用默认占位图。");
return;
}
Log.LogInfo((object)("找到嵌入资源: " + text));
using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(text);
if (stream == null)
{
Log.LogError((object)("无法获取资源流: " + text));
return;
}
MainAssets = AssetBundle.LoadFromStream(stream);
if ((Object)(object)MainAssets == (Object)null)
{
Log.LogError((object)"AssetBundle.LoadFromStream 返回 null,请检查资源文件是否有效。");
}
else
{
Log.LogInfo((object)("AssetBundle 加载成功,包含的资源: " + string.Join(", ", MainAssets.GetAllAssetNames())));
}
}
public void OnDestroy()
{
Harmony obj = harmony;
if (obj != null)
{
obj.UnpatchSelf();
}
}
public void Update()
{
if (Input.GetKeyDown((KeyCode)286))
{
ShowDebugInfo();
}
if (Input.GetKeyDown((KeyCode)287))
{
ForceRecalculate();
}
}
private void InitializePlayerCountManager()
{
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Expected O, but got Unknown
Log.LogInfo((object)"正在初始化 PlayerCountManager...");
if ((Object)(object)PlayerCountManager.Instance != (Object)null)
{
Log.LogWarning((object)"PlayerCountManager 已存在,跳过创建");
return;
}
GameObject val = new GameObject("ShareChest_PlayerCountManager");
val.AddComponent<PlayerCountManager>();
Object.DontDestroyOnLoad((Object)(object)val);
Log.LogInfo((object)"PlayerCountManager 初始化完成");
}
private void InitializeConfiguration()
{
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Expected O, but got Unknown
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
//IL_00a6: Expected O, but got Unknown
//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
//IL_00fa: Expected O, but got Unknown
//IL_014f: Unknown result type (might be due to invalid IL or missing references)
//IL_0159: Expected O, but got Unknown
//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
//IL_01aa: Expected O, but got Unknown
//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
//IL_01fa: Expected O, but got Unknown
Log.LogInfo((object)"正在初始化配置系统...");
ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("通用设置", "启用插件", true, new ConfigDescription("插件总开关。注意:同时需要神器“共享宝箱”启用才能生效。", (AcceptableValueBase)null, new object[1]
{
new ConfigurationManagerAttributes
{
Order = 10,
IsAdvanced = false
}
}));
EnableDynamicMultiplier = ((BaseUnityPlugin)this).Config.Bind<bool>("掉落设置", "启用动态倍率", false, new ConfigDescription("是否根据玩家人数动态调整掉落倍率\n• true = 启用动态倍率(倍率 = 玩家人数)\n• false = 使用固定倍率", (AcceptableValueBase)null, new object[1]
{
new ConfigurationManagerAttributes
{
Order = 15,
IsAdvanced = false
}
}));
FixedMultiplier = ((BaseUnityPlugin)this).Config.Bind<int>("掉落设置", "固定掉落倍率", 5, new ConfigDescription("当'启用动态倍率'为false时使用的固定掉落倍率\n• 1 = 正常掉落(原版行为)\n• 5 = 掉落5个相同物品(推荐)\n• 单人固定倍率推荐1,多人推荐动态倍率\n• 注意:过高的值可能影响游戏性能", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50), new object[1]
{
new ConfigurationManagerAttributes
{
Order = 20,
IsAdvanced = false
}
}));
DropDistanceClamp = ((BaseUnityPlugin)this).Config.Bind<float>("掉落设置", "掉落距离限制", 6f, new ConfigDescription("控制物品掉落时的最小距离限制\n• 默认值为6,不推荐更改\n• 较低的值使物品掉落更集中\n• 较高的值使物品掉落更分散\n• 注意:过高的值可能导致物品飞出太远", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 15f), new object[1]
{
new ConfigurationManagerAttributes
{
Order = 25,
IsAdvanced = false
}
}));
AffectedChestTypes = ((BaseUnityPlugin)this).Config.Bind<string>("宝箱类型设置", "应用倍率的宝箱类型", "Chest1(Clone),Chest2(Clone),GoldChest,LunarChest(Clone),VoidChest(Clone),CategoryChestUtility(Clone),CategoryChest2Utility Variant(Clone),CategoryChestHealing(Clone),CategoryChest2Healing Variant(Clone),CategoryChestDamage(Clone),CategoryChest2Damage Variant(Clone)", new ConfigDescription("指定哪些宝箱类型应用掉落倍率\n• 用逗号分隔多个宝箱类型\n• 常见宝箱类型:\n - Chest1(Clone): 普通宝箱\n - Chest2(Clone): 大宝箱\n - GoldChest: 传奇宝箱\n - LunarChest(Clone): 月球舱\n - VoidChest(Clone): 虚空摇篮\n - EquipmentBarrel(Clone): 装备箱(默认关闭)\n - Lockbox(Clone): 生锈带锁箱(默认关闭)\n - CategoryChestUtility(Clone): 辅助箱\n - CategoryChest2Utility Variant(Clone): 大辅助箱\n - CategoryChestHealing(Clone): 治疗箱\n - CategoryChest2Healing Variant(Clone): 大治疗箱\n - CategoryChestDamage(Clone): 伤害箱\n - CategoryChest2Damage Variant(Clone): 大伤害箱\n• 默认关闭倍率宝箱类型:\n - EquipmentBarrel(Clone): 装备箱\n - Lockbox(Clone): 生锈带锁箱\n• 如需启用请在默认值中添加\n• 留空表示所有宝箱都应用倍率\n• 注意:名字必须完全匹配,包括大小写和括号", (AcceptableValueBase)null, new object[1]
{
new ConfigurationManagerAttributes
{
Order = 80,
IsAdvanced = false
}
}));
EnableDebugLogs = ((BaseUnityPlugin)this).Config.Bind<bool>("调试设置", "启用调试日志", true, new ConfigDescription("启用详细的调试日志输出", (AcceptableValueBase)null, new object[1]
{
new ConfigurationManagerAttributes
{
Order = 1000,
IsAdvanced = true
}
}));
UpdateAffectedChestTypes();
ModEnabled.SettingChanged += delegate
{
LogInfo("插件总开关已变更:" + (ModEnabled.Value ? "启用" : "禁用"));
};
EnableDynamicMultiplier.SettingChanged += delegate
{
LogInfo("倍率模式已变更:" + (EnableDynamicMultiplier.Value ? "动态" : "固定"));
};
FixedMultiplier.SettingChanged += delegate
{
LogInfo($"固定倍率已变更:{FixedMultiplier.Value}x");
};
DropDistanceClamp.SettingChanged += delegate
{
LogInfo($"掉落距离限制已变更:{DropDistanceClamp.Value}");
};
AffectedChestTypes.SettingChanged += delegate
{
UpdateAffectedChestTypes();
};
EnableDebugLogs.SettingChanged += delegate
{
LogInfo("调试日志已" + (EnableDebugLogs.Value ? "启用" : "禁用"));
};
}
private void InitializeArtifacts()
{
Log.LogInfo((object)"正在初始化神器系统...");
IEnumerable<Type> enumerable = from t in Assembly.GetExecutingAssembly().GetTypes()
where !t.IsAbstract && t.IsSubclassOf(typeof(ArtifactBase))
select t;
foreach (Type item in enumerable)
{
ArtifactBase artifactBase = (ArtifactBase)Activator.CreateInstance(item);
if (((BaseUnityPlugin)this).Config.Bind<bool>("神器设置", artifactBase.ArtifactName + "_启用", true, "是否在神器选择界面显示该神器").Value)
{
artifactBase.Init(((BaseUnityPlugin)this).Config);
artifacts.Add(artifactBase);
Log.LogInfo((object)("已加载神器: " + artifactBase.ArtifactName));
}
}
Log.LogInfo((object)$"神器系统初始化完成,共加载 {artifacts.Count} 个神器");
}
private void InitializeHarmonyPatches()
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Expected O, but got Unknown
Log.LogInfo((object)"正在应用 Harmony 补丁...");
harmony = new Harmony("com.Muskmelovon.ShareChest");
harmony.PatchAll(Assembly.GetExecutingAssembly());
IEnumerable<MethodBase> patchedMethods = harmony.GetPatchedMethods();
Log.LogInfo((object)$"成功应用 {patchedMethods.Count()} 个 Harmony 补丁");
}
private static void ShowDebugInfo()
{
int currentPlayerCount = GetCurrentPlayerCount();
int num = CalculateMultiplier(currentPlayerCount);
LogInfo("=== 共享宝箱调试信息 ===");
LogInfo($"插件总开关: {ModEnabled.Value}");
LogInfo($"神器启用状态: {IsArtifactEnabled}");
LogInfo($"当前玩家数量: {currentPlayerCount}");
LogInfo($"动态倍率: {EnableDynamicMultiplier.Value}");
LogInfo($"固定倍率: {FixedMultiplier.Value}");
LogInfo($"掉落距离限制: {DropDistanceClamp.Value}");
LogInfo($"计算后的倍率: {num}x");
LogInfo("PlayerCountManager 实例: " + (((Object)(object)PlayerCountManager.Instance != (Object)null) ? "存在" : "不存在"));
if ((Object)(object)PlayerCountManager.Instance != (Object)null)
{
LogInfo($"PlayerCountManager 计数: {PlayerCountManager.Instance.CurrentPlayerCount}");
}
LogInfo($"宝箱类型白名单: {affectedChestTypeSet.Count}种");
if (affectedChestTypeSet.Count > 0)
{
LogInfo("白名单内容: " + string.Join(", ", affectedChestTypeSet));
}
LogInfo("========================");
}
private static void ForceRecalculate()
{
if ((Object)(object)PlayerCountManager.Instance != (Object)null)
{
PlayerCountManager.Instance.RecalculatePlayerCount();
LogInfo($"已强制重新计算玩家数量: {PlayerCountManager.Instance.CurrentPlayerCount}人");
}
else
{
LogError("PlayerCountManager 实例不存在,无法重新计算");
}
}
public static int CalculateMultiplier(int currentPlayerCount)
{
if (!EnableDynamicMultiplier.Value)
{
return Math.Max(1, FixedMultiplier.Value);
}
return Math.Max(1, currentPlayerCount);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetCurrentPlayerCount()
{
if ((Object)(object)PlayerCountManager.Instance != (Object)null)
{
return PlayerCountManager.Instance.CurrentPlayerCount;
}
try
{
if (NetworkUser.readOnlyInstancesList != null)
{
return NetworkUser.readOnlyInstancesList.Count;
}
if (NetworkServer.active)
{
int num = 0;
foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
{
if ((Object)(object)instance != (Object)null && ((Behaviour)instance).isActiveAndEnabled)
{
num++;
}
}
return Math.Max(1, num);
}
return 1;
}
catch
{
return 1;
}
}
public static string GetMultiplierInfo(int playerCount)
{
if (!EnableDynamicMultiplier.Value)
{
return $"固定倍率: {FixedMultiplier.Value}x";
}
return $"动态倍率: {CalculateMultiplier(playerCount)}x (玩家数: {playerCount}人)";
}
private static void UpdateAffectedChestTypes()
{
affectedChestTypeSet.Clear();
string value = AffectedChestTypes.Value;
if (string.IsNullOrWhiteSpace(value))
{
return;
}
IEnumerable<string> enumerable = from s in value.Split(new string[1] { ChestListSeparator }, StringSplitOptions.RemoveEmptyEntries)
select s.Trim() into s
where !string.IsNullOrEmpty(s)
select s;
foreach (string item in enumerable)
{
affectedChestTypeSet.Add(item);
}
LogDebug($"已加载 {affectedChestTypeSet.Count} 种宝箱类型");
}
public static bool ShouldApplyToChest(string chestName)
{
if (affectedChestTypeSet.Count == 0)
{
return true;
}
return affectedChestTypeSet.Contains(chestName);
}
public static bool ShouldApplyMultiplier(ChestBehavior chest)
{
if (!ModEnabled.Value || !IsArtifactEnabled)
{
LogDebug($"多倍掉落未生效:插件总开关={ModEnabled.Value}, 神器启用={IsArtifactEnabled}");
return false;
}
if ((Object)(object)chest == (Object)null || (Object)(object)((Component)chest).gameObject == (Object)null)
{
return false;
}
string name = ((Object)((Component)chest).gameObject).name;
if (!ShouldApplyToChest(name))
{
LogDebug("宝箱 " + name + " 不在允许列表中,不应用倍率");
return false;
}
Traverse val = Traverse.Create((object)chest);
if (val.Field("isChestOpened").GetValue<bool>())
{
return false;
}
if (chest.isCommandChest)
{
LogDebug("命令宝箱不应用倍率");
return false;
}
int currentPlayerCount = GetCurrentPlayerCount();
int num = CalculateMultiplier(currentPlayerCount);
LogDebug($"将对宝箱 {name} 应用 {num}x 倍率");
return true;
}
public static void LogDebug(string message)
{
if (EnableDebugLogs.Value && Log != null)
{
Log.LogInfo((object)("[调试] " + message));
}
}
public static void LogWarning(string message)
{
ManualLogSource log = Log;
if (log != null)
{
log.LogWarning((object)("[警告] " + message));
}
}
public static void LogError(string message)
{
ManualLogSource log = Log;
if (log != null)
{
log.LogError((object)("[错误] " + message));
}
}
public static void LogInfo(string message)
{
ManualLogSource log = Log;
if (log != null)
{
log.LogInfo((object)("[信息] " + message));
}
}
}
internal class ConfigurationManagerAttributes
{
public int? Order = null;
public bool? IsAdvanced = null;
public string Category = null;
public Action<ConfigEntryBase> CustomDrawer = null;
}
public class PlayerCountManager : MonoBehaviour
{
private float lastRecalculateTime = 0f;
private const float RECALCULATE_INTERVAL = 2f;
public static PlayerCountManager Instance { get; private set; }
public int CurrentPlayerCount { get; private set; }
public bool IsMultiplayer => CurrentPlayerCount > 1;
private void Awake()
{
if ((Object)(object)Instance == (Object)null)
{
Instance = this;
Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
((MonoBehaviour)this).StartCoroutine(DelayedInitialize());
}
else
{
Object.Destroy((Object)(object)((Component)this).gameObject);
}
}
private IEnumerator DelayedInitialize()
{
yield return null;
try
{
NetworkUser.onPostNetworkUserStart += new NetworkUserGenericDelegate(OnPlayerJoined);
NetworkUser.onNetworkUserLost += new NetworkUserGenericDelegate(OnPlayerLost);
SceneManager.activeSceneChanged += OnSceneChanged;
RecalculatePlayerCount();
ShareChestPlugin.LogInfo($"[PlayerCountManager] 初始化完成,当前玩家数: {CurrentPlayerCount}");
((MonoBehaviour)this).InvokeRepeating("PeriodicCheck", 5f, 5f);
}
catch (Exception ex)
{
ShareChestPlugin.LogError("[PlayerCountManager] 初始化失败: " + ex.Message);
}
}
private void OnDestroy()
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Expected O, but got Unknown
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Expected O, but got Unknown
try
{
NetworkUser.onPostNetworkUserStart -= new NetworkUserGenericDelegate(OnPlayerJoined);
NetworkUser.onNetworkUserLost -= new NetworkUserGenericDelegate(OnPlayerLost);
SceneManager.activeSceneChanged -= OnSceneChanged;
}
catch
{
}
if ((Object)(object)Instance == (Object)(object)this)
{
Instance = null;
}
((MonoBehaviour)this).CancelInvoke("PeriodicCheck");
}
private void OnPlayerJoined(NetworkUser joinedUser)
{
((MonoBehaviour)this).StartCoroutine(UpdatePlayerCountDelayed(1f));
ShareChestPlugin.LogInfo("[PlayerCountManager] 玩家加入: " + joinedUser.userName);
}
private void OnPlayerLost(NetworkUser lostUser)
{
((MonoBehaviour)this).StartCoroutine(UpdatePlayerCountDelayed(1f));
ShareChestPlugin.LogInfo("[PlayerCountManager] 玩家离开: " + lostUser?.userName);
}
private void OnSceneChanged(Scene oldScene, Scene newScene)
{
RecalculatePlayerCount();
ShareChestPlugin.LogInfo($"[PlayerCountManager] 场景变化: {((Scene)(ref oldScene)).name} -> {((Scene)(ref newScene)).name}, 玩家数: {CurrentPlayerCount}");
}
private IEnumerator UpdatePlayerCountDelayed(float delay)
{
yield return (object)new WaitForSeconds(delay);
RecalculatePlayerCount();
}
private void PeriodicCheck()
{
if (Time.time - lastRecalculateTime > 2f)
{
RecalculatePlayerCount();
}
}
public void RecalculatePlayerCount()
{
int currentPlayerCount = CurrentPlayerCount;
try
{
if (NetworkUser.readOnlyInstancesList != null && NetworkUser.readOnlyInstancesList.Count >= 0)
{
CurrentPlayerCount = NetworkUser.readOnlyInstancesList.Count;
ShareChestPlugin.LogInfo($"[PlayerCountManager] 通过NetworkUser获取: {CurrentPlayerCount}人");
}
else if (PlayerCharacterMasterController.instances != null && NetworkServer.active)
{
CurrentPlayerCount = 0;
foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
{
if ((Object)(object)instance != (Object)null && ((Behaviour)instance).isActiveAndEnabled)
{
CurrentPlayerCount++;
}
}
ShareChestPlugin.LogDebug($"[PlayerCountManager] 通过PlayerController获取: {CurrentPlayerCount}人");
}
else
{
CurrentPlayerCount = 1;
ShareChestPlugin.LogDebug("[PlayerCountManager] 单人游戏模式: 1人");
}
if (CurrentPlayerCount != currentPlayerCount)
{
ShareChestPlugin.LogInfo($"[PlayerCountManager] 玩家数量变化: {currentPlayerCount} -> {CurrentPlayerCount}");
if (ShareChestPlugin.ModEnabled != null && ShareChestPlugin.ModEnabled.Value && ShareChestPlugin.EnableDynamicMultiplier != null && ShareChestPlugin.EnableDynamicMultiplier.Value)
{
ShareChestPlugin.LogInfo($"动态倍率更新: 当前{CurrentPlayerCount}人, 倍率{ShareChestPlugin.CalculateMultiplier(CurrentPlayerCount)}x");
}
}
lastRecalculateTime = Time.time;
}
catch (Exception ex)
{
ShareChestPlugin.LogError("重新计算玩家数量失败: " + ex.Message);
CurrentPlayerCount = Math.Max(1, currentPlayerCount);
}
}
public void Reset()
{
CurrentPlayerCount = 0;
RecalculatePlayerCount();
}
}
}
namespace ShareChest.Patches
{
[HarmonyPatch]
public static class ChestBehaviorPatches
{
private static readonly HashSet<uint> processedChests = new HashSet<uint>();
private static int totalChestsGenerated = 0;
private static int chestsOpenedCount = 0;
private static float runStartTime = 0f;
private static uint GetChestUniqueId(ChestBehavior chest)
{
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)chest == (Object)null)
{
return 0u;
}
int instanceID = ((Object)chest).GetInstanceID();
Vector3 position = ((Component)chest).transform.position;
int hashCode = ((object)(Vector3)(ref position)).GetHashCode();
return (uint)(instanceID ^ hashCode) & 0x7FFFFFFFu;
}
[HarmonyPatch(typeof(ChestBehavior), "BaseItemDrop")]
[HarmonyPrefix]
private static bool BaseItemDropPrefix(ChestBehavior __instance)
{
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_00ec: 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_018d: Unknown result type (might be due to invalid IL or missing references)
//IL_0192: Unknown result type (might be due to invalid IL or missing references)
//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
try
{
uint chestUniqueId = GetChestUniqueId(__instance);
if (!NetworkServer.active)
{
ShareChestPlugin.LogDebug($"[{chestUniqueId}] 非服务器端,跳过处理");
return true;
}
if (processedChests.Contains(chestUniqueId))
{
ShareChestPlugin.LogDebug($"[{chestUniqueId}] 宝箱已处理过,防止重复");
return false;
}
if (!ShareChestPlugin.ShouldApplyMultiplier(__instance))
{
return true;
}
if ((Object)(object)__instance == (Object)null || (Object)(object)((Component)__instance).gameObject == (Object)null)
{
return true;
}
Traverse val = Traverse.Create((object)__instance);
if (val.Field("isChestOpened").GetValue<bool>())
{
return true;
}
UniquePickup currentPickup = __instance.currentPickup;
if (!((UniquePickup)(ref currentPickup)).isValid)
{
__instance.Roll();
currentPickup = __instance.currentPickup;
if (!((UniquePickup)(ref currentPickup)).isValid)
{
ShareChestPlugin.LogWarning($"[{chestUniqueId}] 无法生成有效掉落物");
return true;
}
}
processedChests.Add(chestUniqueId);
chestsOpenedCount++;
int currentPlayerCount = ShareChestPlugin.GetCurrentPlayerCount();
int num = ShareChestPlugin.CalculateMultiplier(currentPlayerCount);
int dropCount = __instance.dropCount;
int num2 = dropCount * num;
if (num2 <= 0)
{
ShareChestPlugin.LogWarning($"[{chestUniqueId}] 最终掉落数量异常: {num2}");
return false;
}
UniquePickup currentPickup2 = __instance.currentPickup;
Transform dropTransform = __instance.dropTransform ?? ((Component)__instance).transform;
ExecuteMultiDrop(__instance, dropTransform, currentPickup2, num2);
val.Property("currentPickup", (object[])null).SetValue((object)UniquePickup.none);
val.Field("isChestOpened").SetValue((object)true);
__instance.NetworkisChestOpened = true;
Util.PlaySound("Play_ui_item_world_pickup", ((Component)__instance).gameObject);
ShareChestPlugin.LogDebug($"[{chestUniqueId}] 成功生成 {num2} 个掉落物 (原始:{dropCount} × {num})");
return false;
}
catch (Exception ex)
{
ShareChestPlugin.LogError("BaseItemDropPrefix 错误: " + ex.Message + "\n" + ex.StackTrace);
return true;
}
}
[HarmonyPatch(typeof(ChestBehavior), "Open")]
[HarmonyPostfix]
private static void OpenPostfix(ChestBehavior __instance)
{
if (ShareChestPlugin.ModEnabled.Value)
{
uint chestUniqueId = GetChestUniqueId(__instance);
bool flag = processedChests.Contains(chestUniqueId);
Traverse val = Traverse.Create((object)__instance);
bool value = val.Field("isChestOpened").GetValue<bool>();
ShareChestPlugin.LogInfo($"[{chestUniqueId}] Open() 被调用 - 已处理:{flag}, 状态:{value}");
}
}
[HarmonyPatch(typeof(ChestBehavior), "Start")]
[HarmonyPostfix]
private static void StartPostfix(ChestBehavior __instance)
{
if (ShareChestPlugin.ModEnabled.Value)
{
if (runStartTime == 0f)
{
runStartTime = Time.time;
ShareChestPlugin.LogDebug($"新对局开始于: {runStartTime}");
}
totalChestsGenerated++;
uint chestUniqueId = GetChestUniqueId(__instance);
ShareChestPlugin.LogInfo($"[{chestUniqueId}] 宝箱生成 - 总计: {totalChestsGenerated}个, 类型: {((Object)((Component)__instance).gameObject).name}");
LogChestType(__instance);
}
}
[HarmonyPatch(typeof(ChestBehavior), "OnDisable")]
[HarmonyPostfix]
private static void OnDisablePostfix(ChestBehavior __instance)
{
uint chestUniqueId = GetChestUniqueId(__instance);
processedChests.Remove(chestUniqueId);
}
[HarmonyPatch(typeof(Run), "Start")]
[HarmonyPostfix]
private static void RunStartPostfix()
{
processedChests.Clear();
totalChestsGenerated = 0;
chestsOpenedCount = 0;
runStartTime = Time.time;
if ((Object)(object)PlayerCountManager.Instance != (Object)null)
{
PlayerCountManager.Instance.Reset();
}
ShareChestPlugin.LogInfo("===== 新对局开始 =====");
}
[HarmonyPatch(typeof(Run), "OnDestroy")]
[HarmonyPrefix]
private static void RunOnDestroyPrefix()
{
if (totalChestsGenerated > 0)
{
float num = Time.time - runStartTime;
int currentPlayerCount = ShareChestPlugin.GetCurrentPlayerCount();
ShareChestPlugin.LogInfo("===== 对局结束统计 =====");
ShareChestPlugin.LogInfo($"对局时长: {num:F1}秒");
ShareChestPlugin.LogInfo($"玩家数量: {currentPlayerCount}人");
ShareChestPlugin.LogInfo($"生成宝箱总数: {totalChestsGenerated}个");
ShareChestPlugin.LogInfo($"已打开宝箱数: {chestsOpenedCount}个");
ShareChestPlugin.LogInfo($"宝箱打开率: {(float)chestsOpenedCount * 100f / (float)totalChestsGenerated:F1}%");
ShareChestPlugin.LogInfo("==========================");
}
}
private static void LogChestType(ChestBehavior chest)
{
string text = ((Object)((Component)chest).gameObject).name.ToLower();
string text2 = "未知";
if (text.Contains("chest1"))
{
text2 = "普通宝箱";
}
else if (text.Contains("chest2"))
{
text2 = "大型宝箱";
}
else if (text.Contains("equipment"))
{
text2 = "装备桶";
}
else if (text.Contains("lunar"))
{
text2 = "月球宝箱";
}
else if (text.Contains("void"))
{
text2 = "虚空宝箱";
}
else if (text.Contains("category"))
{
text2 = "分类宝箱";
}
ShareChestPlugin.LogDebug("宝箱类型识别: " + text + " → " + text2);
}
private static void ExecuteMultiDrop(ChestBehavior chest, Transform dropTransform, UniquePickup basePickup, int dropCount)
{
//IL_0028: 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_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//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_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: 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_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: 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_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
//IL_00b0: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
//IL_00b9: 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_00c3: Unknown result type (might be due to invalid IL or missing references)
//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
try
{
float num = 360f / (float)dropCount;
float value = ShareChestPlugin.DropDistanceClamp.Value;
float num2 = Mathf.Clamp(chest.dropForwardVelocityStrength, value, 7f);
Vector3 val = Vector3.up * chest.dropUpVelocityStrength + Vector3.forward * num2;
Quaternion val2 = Quaternion.AngleAxis(num, Vector3.up);
Vector3 val3 = val;
for (int i = 0; i < dropCount; i++)
{
CreatePickupInfo val4 = default(CreatePickupInfo);
((CreatePickupInfo)(ref val4)).pickup = basePickup;
val4.position = dropTransform.position + Vector3.up * 1.5f;
val4.chest = chest;
val4.artifactFlag = (PickupArtifactFlag)(chest.isCommandChest ? 1 : 0);
CreatePickupInfo val5 = val4;
CreatePickupDropletSafe(val5, val5.position, val3);
val3 = val2 * val3;
}
}
catch (Exception ex)
{
ShareChestPlugin.LogError("ExecuteMultiDrop 错误: " + ex.Message);
throw;
}
}
private static void CreatePickupDropletSafe(CreatePickupInfo pickupInfo, Vector3 position, Vector3 velocity)
{
//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
//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_00bc: 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_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: 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_0067: 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)
try
{
MethodInfo method = typeof(PickupDropletController).GetMethod("CreatePickupDroplet", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[3]
{
typeof(CreatePickupInfo),
typeof(Vector3),
typeof(Vector3)
}, null);
if (method != null)
{
method.Invoke(null, new object[3] { pickupInfo, position, velocity });
}
else
{
PickupDropletController.CreatePickupDroplet(((CreatePickupInfo)(ref pickupInfo)).pickup.pickupIndex, position, velocity);
}
}
catch (Exception ex)
{
ShareChestPlugin.LogError("创建掉落物失败: " + ex.Message);
try
{
PickupDropletController.CreatePickupDroplet(((CreatePickupInfo)(ref pickupInfo)).pickup.pickupIndex, position, velocity);
}
catch
{
ShareChestPlugin.LogError("备用创建方案也失败");
}
}
}
}
}