using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using Agents;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Unity.IL2CPP;
using BepInEx.Unity.IL2CPP.Utils;
using CellMenu;
using Enemies;
using GameData;
using HarmonyLib;
using Hikaria.MagicRinObserver.Config;
using Hikaria.MagicRinObserver.Ext;
using Hikaria.MagicRinObserver.Lang;
using Hikaria.MagicRinObserver.Managers;
using Hikaria.MagicRinObserver.Patches;
using Hikaria.MagicRinObserver.Utils;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using LevelGeneration;
using Player;
using SNetwork;
using UnityEngine;
using UnityEngine.Networking;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("Hikaria / MagicRinObserverCompat")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("MagicRinObserverCompat")]
[assembly: AssemblyTitle("MagicRinObserverCompat")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Hikaria.MagicRinObserver
{
[BepInPlugin("MagicRinObserverCompat", "MagicRinObserverCompat", "1.0.0")]
internal class EntryPoint : BasePlugin
{
private Settings _settings;
public static EntryPoint Instance { get; private set; }
public static Settings Settings
{
get
{
if (Instance._settings == null)
{
Instance._settings = new Settings();
Instance._settings.Setup();
}
return Instance._settings;
}
}
public override void Load()
{
Instance = this;
Init();
RegisterTypesInIl2Cpp();
RegisterPatchesInHarmony();
Logs.LogMessage(Settings.Language.LOADED);
}
private void RegisterTypesInIl2Cpp()
{
ClassInjector.RegisterTypeInIl2Cpp<ChatManager>();
ClassInjector.RegisterTypeInIl2Cpp<GameEventLogManager>();
}
private void RegisterPatchesInHarmony()
{
Patch.RegisterPatch<ChatCommand>();
Patch.RegisterPatch<PlayerJoinLobby>();
Patch.RegisterPatch<EnemyWakeup>();
Patch.RegisterPatch<FriendlyFire>();
Patch.RegisterPatch<PlayerSlip>();
Patch.RegisterPatch<SecurityDoorState>();
Patch.RegisterPatch<GiveResource>();
Patch.RegisterPatch<PlayerUnderAttack>();
Patch.RegisterPatch<EnemyUnderAttack>();
}
private void Init()
{
if (Instance._settings == null)
{
Instance._settings = new Settings();
}
Instance._settings.Setup();
TranslateManager.Init();
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "MagicRinObserverCompat";
public const string PLUGIN_NAME = "MagicRinObserverCompat";
public const string PLUGIN_VERSION = "1.0.0";
public const string PLUGIN_AUTHOR = "<#27C6E0>花城あんず";
public const int PLUGIN_INTERNAL_VERSION = 10006;
}
}
namespace Hikaria.MagicRinObserver.Utils
{
internal static class HttpHelper
{
public static void Get(string url, Action<UnityWebRequest> OnSuccess, Action<UnityWebRequest> OnFailed = null)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Expected O, but got Unknown
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Expected O, but got Unknown
if ((Object)CoroutineManager.Current == (Object)null)
{
Logs.LogError("CoroutineManager 为空!");
}
else
{
MonoBehaviourExtensions.StartCoroutine((MonoBehaviour)CoroutineManager.Current, getFromURL(url, OnSuccess, OnFailed));
}
}
private static IEnumerator getFromURL(string url, Action<UnityWebRequest> OnSuccess, Action<UnityWebRequest> OnFailed = null)
{
UnityWebRequest request = UnityWebRequest.Get(url);
request.timeout = 10;
yield return request.SendWebRequest();
if (!request.isDone || request.isHttpError || request.isNetworkError)
{
OnFailed?.Invoke(request);
request.Dispose();
}
else
{
OnSuccess?.Invoke(request);
request.Dispose();
}
}
}
internal class JsonConverter
{
public JsonSerializerOptions Options;
public JsonConverter()
{
Options = new JsonSerializerOptions
{
AllowTrailingCommas = true,
IncludeFields = true,
PropertyNameCaseInsensitive = true,
ReadCommentHandling = JsonCommentHandling.Skip,
WriteIndented = true
};
Options.Converters.Add(new JsonStringEnumConverter());
}
public JsonConverter(bool allowTrailingCommas = true, bool includeFields = true, bool propertyNameCaseInsensitive = true, bool writeIndented = true)
{
Options = new JsonSerializerOptions
{
AllowTrailingCommas = allowTrailingCommas,
IncludeFields = includeFields,
PropertyNameCaseInsensitive = propertyNameCaseInsensitive,
ReadCommentHandling = JsonCommentHandling.Skip,
WriteIndented = writeIndented
};
Options.Converters.Add(new JsonStringEnumConverter());
}
public void TryRead<T>(string path, out T output) where T : new()
{
if (File.Exists(path))
{
string json = File.ReadAllText(path);
output = Deserialize<T>(json);
}
else
{
output = new T();
string contents = Serialize(output);
File.WriteAllText(path, contents);
}
}
public string Serialize(object value)
{
return JsonSerializer.Serialize(value, Options);
}
public T Deserialize<T>(string json)
{
return JsonSerializer.Deserialize<T>(json, Options);
}
}
internal static class Logs
{
public static void LogDebug(object data)
{
((BasePlugin)EntryPoint.Instance).Log.LogDebug(data);
}
public static void LogError(object data)
{
((BasePlugin)EntryPoint.Instance).Log.LogError(data);
}
public static void LogFatal(object data)
{
((BasePlugin)EntryPoint.Instance).Log.LogFatal(data);
}
public static void LogInfo(object data)
{
((BasePlugin)EntryPoint.Instance).Log.LogInfo(data);
}
public static void LogMessage(object data)
{
((BasePlugin)EntryPoint.Instance).Log.LogMessage(data);
}
public static void LogWarning(object data)
{
((BasePlugin)EntryPoint.Instance).Log.LogWarning(data);
}
}
internal abstract class Patch
{
public enum PatchType : byte
{
Prefix = 1,
Postfix,
Both
}
private protected static readonly Dictionary<Type, Patch> RegisteredPatches = new Dictionary<Type, Patch>();
private protected static Harmony _Harmony;
protected internal Harmony Harmony { get; set; }
public virtual bool Enabled => true;
public abstract string PatchName { get; }
public virtual void Initialize()
{
}
public abstract void Execute();
public void PatchConstructor<TClass>(PatchType patchType, string prefixMethodName = null, string postfixMethodName = null) where TClass : class
{
PatchConstructor<TClass>(null, patchType, prefixMethodName, postfixMethodName);
}
public void PatchConstructor<TClass>(Type[] parameters, PatchType patchType, string prefixMethodName = null, string postfixMethodName = null) where TClass : class
{
ConstructorInfo methodBase = AccessTools.Constructor(typeof(TClass), parameters, false);
PatchMethod<TClass>(methodBase, patchType, prefixMethodName, postfixMethodName);
}
public void PatchMethod<TClass>(string methodName, PatchType patchType, Type[] generics = null, string prefixMethodName = null, string postfixMethodName = null) where TClass : class
{
PatchMethod<TClass>(methodName, null, patchType, generics, prefixMethodName, postfixMethodName);
}
public void PatchMethod<TClass>(string methodName, Type[] parameters, PatchType patchType, Type[] generics = null, string prefixMethodName = null, string postfixMethodName = null) where TClass : class
{
MethodInfo methodBase = AccessTools.Method(typeof(TClass), methodName, parameters, generics);
PatchMethod<TClass>(methodBase, patchType, prefixMethodName, postfixMethodName);
}
public void PatchMethod<TClass>(MethodBase methodBase, PatchType patchType, string prefixMethodName = null, string postfixMethodName = null) where TClass : class
{
PatchMethod(typeof(TClass), methodBase, patchType, prefixMethodName, postfixMethodName);
}
public void PatchMethod(Type classType, string methodName, PatchType patchType, Type[] generics = null, string prefixMethodName = null, string postfixMethodName = null)
{
PatchMethod(classType, methodName, null, patchType, generics, prefixMethodName, postfixMethodName);
}
public void PatchMethod(Type classType, string methodName, Type[] parameters, PatchType patchType, Type[] generics = null, string prefixMethodName = null, string postfixMethodName = null)
{
MethodInfo methodBase = AccessTools.Method(classType, methodName, parameters, generics);
PatchMethod(classType, methodBase, patchType, prefixMethodName, postfixMethodName);
}
public void PatchMethod(Type classType, MethodBase methodBase, PatchType patchType, string prefixMethodName = null, string postfixMethodName = null)
{
//IL_015f: Unknown result type (might be due to invalid IL or missing references)
//IL_016d: Expected O, but got Unknown
//IL_0136: Unknown result type (might be due to invalid IL or missing references)
//IL_013c: Unknown result type (might be due to invalid IL or missing references)
//IL_0149: Expected O, but got Unknown
//IL_0149: Expected O, but got Unknown
//IL_0182: Unknown result type (might be due to invalid IL or missing references)
//IL_018f: Expected O, but got Unknown
string text = classType.Name.Replace("`", "__");
string value = methodBase.ToString();
string text2 = (methodBase.IsConstructor ? "ctor" : methodBase.Name);
MethodInfo methodInfo = null;
MethodInfo methodInfo2 = null;
if ((int)(patchType & PatchType.Prefix) > 0)
{
try
{
methodInfo2 = AccessTools.Method(GetType(), prefixMethodName ?? (text + "__" + text2 + "__Prefix"), (Type[])null, (Type[])null);
}
catch (Exception value2)
{
Logs.LogError($"未能获得 ({value}) 的前缀补丁方法: {value2}");
}
}
if ((int)(patchType & PatchType.Postfix) > 0)
{
try
{
methodInfo = AccessTools.Method(GetType(), postfixMethodName ?? (text + "__" + text2 + "__Postfix"), (Type[])null, (Type[])null);
}
catch (Exception value3)
{
Logs.LogError($"未能获得 ({value}) 的后缀补丁方法: {value3}");
}
}
try
{
if (methodInfo2 != null && methodInfo != null)
{
Harmony.Patch(methodBase, new HarmonyMethod(methodInfo2), new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
else if (methodInfo2 != null)
{
Harmony.Patch(methodBase, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
else if (methodInfo != null)
{
Harmony.Patch(methodBase, (HarmonyMethod)null, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
}
catch (Exception value4)
{
Logs.LogError($"无法为 {value} 方法打补丁: {value4}");
}
}
public static void UnpatchSelf()
{
_Harmony.UnpatchSelf();
Logs.LogError("Harmony: UnpatchSelf!");
}
public static void RegisterPatch<T>() where T : Patch, new()
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Expected O, but got Unknown
if (_Harmony == null)
{
_Harmony = new Harmony("MagicRinObserverCompat");
}
if (RegisteredPatches.ContainsKey(typeof(T)))
{
Logs.LogMessage(string.Format(EntryPoint.Settings.Language.IGNORE_REPEAT_PATCH, typeof(T).Name));
return;
}
T val = new T
{
Harmony = _Harmony
};
val.Initialize();
if (val.Enabled)
{
Logs.LogMessage(string.Format(EntryPoint.Settings.Language.PATCHING, val.PatchName));
val.Execute();
}
RegisteredPatches[typeof(T)] = val;
}
}
}
namespace Hikaria.MagicRinObserver.Patches
{
internal class ChatCommand : Patch
{
private const string _prefix = "/magicrin";
private CommandManager _commandManager;
public override string PatchName => "ChatCommand";
public static ChatCommand Instance { get; private set; }
public override void Initialize()
{
Instance = this;
_commandManager = new CommandManager("/magicrin");
}
public override void Execute()
{
PatchMethod<PlayerChatManager>("PostMessage", PatchType.Prefix);
RegisterCommand("check", delegate
{
CheckSettings();
}, "检查功能启用状态");
}
private static void PlayerChatManager__PostMessage__Prefix(PlayerChatManager __instance)
{
string text = __instance.m_currentValue.ToLower();
if (!text.StartsWith("/magicrin"))
{
return;
}
try
{
List<string> list = text.Split(' ').ToList();
list.RemoveAt(0);
string key = list[0];
list.RemoveAt(0);
if (!Instance._commandManager.TryExcuteCommand(key, list.ToArray()))
{
throw new Exception("输入有误");
}
}
catch (Exception ex)
{
Logs.LogError(ex.Message);
Logs.LogError("输入信息: " + text);
GameEventLogManager.AddLog(EntryPoint.Settings.Language.COMMAND_WRONG_INPUT);
GameEventLogManager.AddLog(EntryPoint.Settings.Language.COMMAND_LIST);
}
finally
{
__instance.m_currentValue = "";
}
}
public static void RegisterCommand(string key, Action<string[]> callback, string commandHelp)
{
Instance._commandManager.AddCommand(key, callback, commandHelp);
}
private static void CheckSettings()
{
GameEventLogManager.AddLog(EntryPoint.Settings.Language.SETTINGS_CHECK);
GameEventLogManager.AddLog(string.Format(EntryPoint.Settings.Language.DETECTION_ENEMYWAKEUP + " <color={0}>[{1}]</color>", (EntryPoint.Settings.EnemyWakeupEnable && SNet.IsMaster) ? "green" : "red", (EntryPoint.Settings.EnemyWakeupEnable && SNet.IsMaster) ? EntryPoint.Settings.Language.ENABLED : EntryPoint.Settings.Language.DISABLED));
GameEventLogManager.AddLog(string.Format(EntryPoint.Settings.Language.DETECTION_FRIENDLYFIRE + " <color={0}>[{1}]</color>", (EntryPoint.Settings.FriendlyFireEnable && SNet.IsMaster) ? "green" : "red", (EntryPoint.Settings.FriendlyFireEnable && SNet.IsMaster) ? EntryPoint.Settings.Language.ENABLED : EntryPoint.Settings.Language.DISABLED));
GameEventLogManager.AddLog(string.Format(EntryPoint.Settings.Language.DETECTION_PLAYERSLIP + " <color={0}>[{1}]</color>", (EntryPoint.Settings.SlipEnable && SNet.IsMaster) ? "green" : "red", (EntryPoint.Settings.SlipEnable && SNet.IsMaster) ? EntryPoint.Settings.Language.ENABLED : EntryPoint.Settings.Language.DISABLED));
GameEventLogManager.AddLog(string.Format(EntryPoint.Settings.Language.DETECTION_DOORSTATE + " <color={0}>[{1}]</color>", (EntryPoint.Settings.DoorStateEnable && SNet.IsMaster) ? "green" : "red", (EntryPoint.Settings.DoorStateEnable && SNet.IsMaster) ? EntryPoint.Settings.Language.ENABLED : EntryPoint.Settings.Language.DISABLED));
GameEventLogManager.AddLog(string.Format(EntryPoint.Settings.Language.DETECTION_GIVERESOURCE + " <color={0}>[{1}]</color>", (EntryPoint.Settings.GiveResourceEnable && SNet.IsMaster) ? "green" : "red", (EntryPoint.Settings.GiveResourceEnable && SNet.IsMaster) ? EntryPoint.Settings.Language.ENABLED : EntryPoint.Settings.Language.DISABLED));
GameEventLogManager.AddLog(string.Format(EntryPoint.Settings.Language.DETECTION_POUNCERCONSUME + " <color={0}>[{1}]</color>", (EntryPoint.Settings.PouncerConsumeEnable && SNet.IsMaster) ? "green" : "red", (EntryPoint.Settings.PouncerConsumeEnable && SNet.IsMaster) ? EntryPoint.Settings.Language.ENABLED : EntryPoint.Settings.Language.DISABLED));
GameEventLogManager.AddLog(string.Format(EntryPoint.Settings.Language.DETECTION_KILLTIMER + " <color={0}>[{1}]</color>", (EntryPoint.Settings.EnemyUnderAttackKillTimerEnable && SNet.IsMaster) ? "green" : "red", (EntryPoint.Settings.EnemyUnderAttackKillTimerEnable && SNet.IsMaster) ? EntryPoint.Settings.Language.ENABLED : EntryPoint.Settings.Language.DISABLED));
}
public static bool StringToBool(string param)
{
param = param.ToLower();
if (param == "on")
{
return true;
}
if (!(param == "off"))
{
throw new Exception("非法输入");
}
return false;
}
}
internal class EnemyUnderAttack : Patch
{
public class Timer
{
private int _sec = 10;
private int _num = 1;
public void add()
{
}
public void Start()
{
while (_sec > 0)
{
Thread.Sleep(250);
_sec--;
}
}
}
private static readonly Dictionary<int, Stopwatch> registeredKillTimer = new Dictionary<int, Stopwatch>();
private static readonly Dictionary<int, Dictionary<int, float>> registeredKillTimerDamageStat = new Dictionary<int, Dictionary<int, float>>();
private static readonly Dictionary<string, Thread> alerts = new Dictionary<string, Thread>();
private static readonly Dictionary<string, Timer> alertsInstance = new Dictionary<string, Timer>();
private static readonly Dictionary<uint, string> killTimerEnemyNameIDs = new Dictionary<uint, string>();
private static readonly string CONFIG_KILLTIMER_ENEMYNAMEID = Paths.ConfigPath + "\\MagicRinObserver\\KillTimerEnemyNameIDs.json";
public override string PatchName => "EnemyUnderAttack";
public static EnemyUnderAttack Instance { get; private set; }
public override void Initialize()
{
Instance = this;
Init();
}
public override void Execute()
{
PatchMethod<Dam_EnemyDamageBase>("ProcessReceivedDamage", PatchType.Prefix);
ChatCommand.RegisterCommand("kt", delegate(string[] parameters)
{
bool enemyUnderAttackKillTimerEnable = ChatCommand.StringToBool(parameters[0]);
EntryPoint.Settings.EnemyUnderAttackKillTimerEnable = enemyUnderAttackKillTimerEnable;
GameEventLogManager.AddLog(string.Format("<color=orange>[MagicRinObserver]</color> <color={0}>" + EntryPoint.Settings.Language.DETECTION_KILLTIMER + " {1}</color>", EntryPoint.Settings.EnemyUnderAttackKillTimerEnable ? "green" : "red", EntryPoint.Settings.EnemyUnderAttackKillTimerEnable ? EntryPoint.Settings.Language.ENABLED : EntryPoint.Settings.Language.DISABLED));
}, "[on|off], " + EntryPoint.Settings.Language.ENABLED + "|" + EntryPoint.Settings.Language.DISABLED + " " + EntryPoint.Settings.Language.DETECTION_KILLTIMER);
}
private static void Dam_EnemyDamageBase__ProcessReceivedDamage__Prefix(Dam_EnemyDamageBase __instance, Agent damageSource, float damage)
{
if (SNet.IsMaster && EntryPoint.Settings.EnemyUnderAttackKillTimerEnable && (Object)(object)damageSource != (Object)null)
{
StartKillTimer(__instance, damageSource, damage);
}
}
private static void Init()
{
killTimerEnemyNameIDs.Clear();
new Hikaria.MagicRinObserver.Utils.JsonConverter().TryRead<List<TranslateManager.EnemyNameID>>(CONFIG_KILLTIMER_ENEMYNAMEID, out var output);
foreach (TranslateManager.EnemyNameID item in output)
{
foreach (uint iD in item.IDs)
{
killTimerEnemyNameIDs.Add(iD, item.Name);
}
}
}
private static void StartKillTimer(Dam_EnemyDamageBase __instance, Agent damageSource, float damage)
{
EnemyAgent enemy = __instance.Owner;
damage = ((damage <= ((Dam_SyncedDamageBase)enemy.Damage).Health) ? damage : ((Dam_SyncedDamageBase)enemy.Damage).Health);
int key = damageSource.m_replicator.OwningPlayer.PlayerSlotIndex();
if (!registeredKillTimerDamageStat.ContainsKey(((Object)enemy).GetInstanceID()))
{
registeredKillTimerDamageStat.Add(((Object)enemy).GetInstanceID(), new Dictionary<int, float>());
}
if (!registeredKillTimerDamageStat[((Object)enemy).GetInstanceID()].ContainsKey(key))
{
registeredKillTimerDamageStat[((Object)enemy).GetInstanceID()].Add(key, damage);
}
else
{
registeredKillTimerDamageStat[((Object)enemy).GetInstanceID()][key] += damage;
}
if (!killTimerEnemyNameIDs.ContainsKey(enemy.EnemyDataID) || registeredKillTimer.ContainsKey(((Object)enemy).GetInstanceID()))
{
return;
}
Stopwatch timer = new Stopwatch();
int instanceID = ((Object)enemy).GetInstanceID();
registeredKillTimer.Add(instanceID, timer);
timer.Start();
enemy.OnDeadCallback += Action.op_Implicit((Action)delegate
{
if (registeredKillTimer.ContainsKey(instanceID))
{
timer.Stop();
float num = (registeredKillTimerDamageStat[instanceID].ContainsKey(0) ? registeredKillTimerDamageStat[instanceID][0] : 0f);
float num2 = (registeredKillTimerDamageStat[instanceID].ContainsKey(1) ? registeredKillTimerDamageStat[instanceID][1] : 0f);
float num3 = (registeredKillTimerDamageStat[instanceID].ContainsKey(2) ? registeredKillTimerDamageStat[instanceID][2] : 0f);
float num4 = (registeredKillTimerDamageStat[instanceID].ContainsKey(3) ? registeredKillTimerDamageStat[instanceID][3] : 0f);
float healthMax = ((Dam_SyncedDamageBase)enemy.Damage).HealthMax;
ChatManager.AddQueue(string.Format(EntryPoint.Settings.EnemyUnderAttackKillTimerText, killTimerEnemyNameIDs[enemy.EnemyDataID], $"{timer.Elapsed.TotalSeconds:0.00}"));
ChatManager.AddQueue($"red: {(int)Math.Round(num)}({(int)Math.Round(num / healthMax * 100f)}%), green: {(int)Math.Round(num2)}({(int)Math.Round(num2 / healthMax * 100f)}%)");
ChatManager.AddQueue($"blue: {(int)Math.Round(num3)}({(int)Math.Round(num3 / healthMax * 100f)}%), purple: {(int)Math.Round(num4)}({(int)Math.Round(num4 / healthMax * 100f)}%)");
registeredKillTimer.Remove(instanceID);
registeredKillTimerDamageStat.Remove(instanceID);
}
});
}
}
internal class EnemyWakeup : Patch
{
public class Timer
{
private int _sec = 3;
private int _num = 1;
public void Start(SNet_Player player, EnemyAgent enemy)
{
while (_sec > 0)
{
Thread.Sleep(1000);
_sec--;
}
ChatManager.AddQueueInSeparate(string.Format(EntryPoint.Settings.EnemyWakeupText, new object[3]
{
player.NickName,
_num,
TranslateManager.EnemyName(enemy.EnemyDataID)
}));
}
public void add()
{
_num++;
_sec = 3;
}
}
private static readonly Dictionary<string, Thread> alerts = new Dictionary<string, Thread>();
private static readonly Dictionary<string, Timer> alertsInstance = new Dictionary<string, Timer>();
public override string PatchName => "EnemyWakeup";
public static EnemyWakeup Instance { get; private set; }
public override void Initialize()
{
Instance = this;
}
public override void Execute()
{
PatchMethod<EnemyDetection>("UpdateHibernationDetection", PatchType.Postfix);
PatchMethod<ES_ScoutScream>("ActivateState", PatchType.Postfix);
ChatCommand.RegisterCommand("wakeup", delegate(string[] parameters)
{
bool enemyWakeupEnable = ChatCommand.StringToBool(parameters[0]);
EntryPoint.Settings.EnemyWakeupEnable = enemyWakeupEnable;
GameEventLogManager.AddLog(string.Format("<color=orange>[MagicRinObserver]</color> <color={0}>" + EntryPoint.Settings.Language.DETECTION_ENEMYWAKEUP + " {1}</color>", EntryPoint.Settings.EnemyWakeupEnable ? "green" : "red", EntryPoint.Settings.EnemyWakeupEnable ? EntryPoint.Settings.Language.ENABLED : EntryPoint.Settings.Language.DISABLED));
}, "[on|off], " + EntryPoint.Settings.Language.ENABLED + "|" + EntryPoint.Settings.Language.DISABLED + " " + EntryPoint.Settings.Language.DETECTION_ENEMYWAKEUP);
}
private static void EnemyDetection__UpdateHibernationDetection__Postfix(EnemyDetection __instance, AgentTarget target, bool __result)
{
if (SNet.IsMaster && EntryPoint.Settings.EnemyWakeupEnable && __result)
{
OnEnemyWakeup(__instance, target);
}
}
private static void ES_ScoutScream__ActivateState__Postfix(ES_ScoutScream __instance, AgentTarget agentTarget)
{
if (SNet.IsMaster && EntryPoint.Settings.EnemyWakeupEnable)
{
OnEnemyWakeup(__instance, agentTarget);
}
}
private static void OnEnemyWakeup(EnemyDetection __instance, AgentTarget target)
{
EnemyAgent enemyAgent = __instance.m_ai.m_enemyAgent;
if (!enemyAgent.IsScout)
{
SNet_Player owningPlayer = target.m_agent.m_replicator.OwningPlayer;
string text = TranslateManager.EnemyName(enemyAgent.EnemyDataID);
string text2 = ((Object)owningPlayer).name + text;
if (!alerts.ContainsKey(text2))
{
CreateThread(owningPlayer, enemyAgent, text2, add: true);
}
else if (alerts[text2].IsAlive)
{
alertsInstance[text2].add();
}
else
{
CreateThread(owningPlayer, enemyAgent, text2, add: false);
}
}
}
private static void OnEnemyWakeup(ES_ScoutScream __instance, AgentTarget target)
{
EnemyAgent enemyAgent = ((ES_Base)__instance).m_ai.m_enemyAgent;
SNet_Player owningPlayer = target.m_agent.m_replicator.OwningPlayer;
string text = TranslateManager.EnemyName(enemyAgent.EnemyDataID);
string text2 = ((Object)owningPlayer).name + text;
if (!alerts.ContainsKey(text2))
{
CreateThread(owningPlayer, enemyAgent, text2, add: true);
}
else if (alerts[text2].IsAlive)
{
alertsInstance[text2].add();
}
else
{
CreateThread(owningPlayer, enemyAgent, text2, add: false);
}
}
private static void CreateThread(SNet_Player player, EnemyAgent enemy, string threadName, bool add)
{
Timer timer = new Timer();
Thread thread = new Thread((ThreadStart)delegate
{
timer.Start(player, enemy);
});
thread.Start();
if (add)
{
alerts.Add(threadName, thread);
alertsInstance.Add(threadName, timer);
}
else
{
alerts[threadName] = thread;
alertsInstance[threadName] = timer;
}
}
}
internal class FriendlyFire : Patch
{
public class Timer
{
private int _sec = 3;
private int _num = 1;
private float _damage;
public Timer(float damage)
{
_damage = damage;
}
public void Start(SNet_Player fromPlayer, SNet_Player toPlayer)
{
while (_sec > 0)
{
Thread.Sleep(1000);
_sec--;
}
ChatManager.AddQueueInSeparate(string.Format(EntryPoint.Settings.FriendlyFireText, fromPlayer.NickName, toPlayer.NickName, _num, (int)_damage));
}
public void add(float damage)
{
_num++;
_sec = 3;
_damage += damage;
}
}
private static Dictionary<string, Thread> alerts = new Dictionary<string, Thread>();
private static Dictionary<string, Timer> alertsInstance = new Dictionary<string, Timer>();
public override string PatchName => "FriendlyFire";
public static FriendlyFire Instance { get; private set; }
public override void Initialize()
{
Instance = this;
}
public override void Execute()
{
PatchMethod<Dam_PlayerDamageBase>("ReceiveBulletDamage", PatchType.Postfix);
PatchMethod<Dam_PlayerDamageBase>("ReceiveExplosionDamage", PatchType.Postfix);
ChatCommand.RegisterCommand("ff", delegate(string[] parameters)
{
bool friendlyFireEnable = ChatCommand.StringToBool(parameters[0]);
EntryPoint.Settings.FriendlyFireEnable = friendlyFireEnable;
GameEventLogManager.AddLog(string.Format("<color=orange>[MagicRinObserver]</color> <color={0}>" + EntryPoint.Settings.Language.DETECTION_FRIENDLYFIRE + " {1}</color>", EntryPoint.Settings.FriendlyFireEnable ? "green" : "red", EntryPoint.Settings.FriendlyFireEnable ? EntryPoint.Settings.Language.ENABLED : EntryPoint.Settings.Language.DISABLED));
}, "[on|off], " + EntryPoint.Settings.Language.ENABLED + "|" + EntryPoint.Settings.Language.DISABLED + " " + EntryPoint.Settings.Language.DETECTION_FRIENDLYFIRE);
}
private static void CreateThread(SNet_Player fromPlayer, SNet_Player toPlayer, float damage, string threadName, bool add)
{
Timer timer = new Timer(damage);
Thread thread = new Thread((ThreadStart)delegate
{
timer.Start(fromPlayer, toPlayer);
});
thread.Start();
if (add)
{
alerts.Add(threadName, thread);
alertsInstance.Add(threadName, timer);
}
else
{
alerts[threadName] = thread;
alertsInstance[threadName] = timer;
}
}
private static void OnBulletDamage(pBulletDamageData data, Dam_PlayerDamageBase __instance)
{
SNet_Player owner = __instance.Owner.Owner;
IReplicator val = default(IReplicator);
((pReplicator)(ref data.source.pRep)).TryGetID(ref val);
SNet_Player owningPlayer = val.OwningPlayer;
float damage = ((UFloat16)(ref data.damage)).Get(100f);
string text = ((Object)owningPlayer).name + ((Object)owner).name;
if (!alerts.ContainsKey(text))
{
CreateThread(owningPlayer, owner, damage, text, add: true);
}
else if (alerts[text].IsAlive)
{
alertsInstance[text].add(damage);
}
else
{
CreateThread(owningPlayer, owner, damage, text, add: false);
}
}
private static void Dam_PlayerDamageBase__ReceiveExplosionDamage__Postfix(pExplosionDamageData data, Dam_PlayerDamageBase __instance)
{
if (EntryPoint.Settings.FriendlyFireEnable && SNet.IsMaster)
{
ChatManager.AddQueueInSeparate(string.Format(EntryPoint.Settings.FriendlyFireExplosionText, __instance.Owner.Owner.NickName, (int)((UFloat16)(ref data.damage)).Get(100f)));
}
}
private static void Dam_PlayerDamageBase__ReceiveBulletDamage__Postfix(pBulletDamageData data, Dam_PlayerDamageBase __instance)
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
if (EntryPoint.Settings.FriendlyFireEnable && SNet.IsMaster)
{
OnBulletDamage(data, __instance);
}
}
}
internal class GiveResource : Patch
{
public class Timer
{
private int _sec = 5;
private int _num = 1;
public void add()
{
_num++;
_sec = 5;
}
public void Start(SNet_Player fromPlayer, SNet_Player toPlayer, ResourcePackType resourcePackType)
{
while (_sec > 0)
{
Thread.Sleep(1000);
_sec--;
}
string text = toPlayer.NickName;
if (fromPlayer.Lookup == toPlayer.Lookup)
{
text = EntryPoint.Settings.Language.SELF;
}
switch (resourcePackType)
{
case ResourcePackType.Medipack:
ChatManager.AddQueue(string.Format(EntryPoint.Settings.GiveResourceHealthText, fromPlayer.NickName, text, _num, toPlayer.NickName));
break;
case ResourcePackType.DisinfectionPack:
ChatManager.AddQueue(string.Format(EntryPoint.Settings.GiveResourceDisinfectionText, fromPlayer.NickName, text, _num, toPlayer.NickName));
break;
case ResourcePackType.AmmoPack:
ChatManager.AddQueue(string.Format(EntryPoint.Settings.GiveResourceAmmoText, fromPlayer.NickName, text, _num, EntryPoint.Settings.Language.WEAPON, toPlayer.NickName));
break;
case ResourcePackType.ToolPack:
ChatManager.AddQueue(string.Format(EntryPoint.Settings.GiveResourceAmmoText, fromPlayer.NickName, text, _num, EntryPoint.Settings.Language.TOOL, toPlayer.NickName));
break;
}
}
}
public enum ResourcePackType : byte
{
Medipack,
AmmoPack,
ToolPack,
DisinfectionPack
}
private static bool localGive = false;
private static readonly Dictionary<string, Thread> alerts = new Dictionary<string, Thread>();
private static readonly Dictionary<string, Timer> alertsInstance = new Dictionary<string, Timer>();
public override string PatchName => "GiveResource";
public static GiveResource Instance { get; private set; }
public override void Initialize()
{
Instance = this;
}
public override void Execute()
{
PatchMethod<Dam_PlayerDamageBase>("ReceiveAddHealth", PatchType.Prefix);
PatchMethod<PlayerBackpackManager>("ReceiveAmmoGive", PatchType.Prefix);
PatchMethod<Dam_PlayerDamageBase>("ModifyInfection", PatchType.Prefix);
PatchMethod<PlayerAgent>("GiveAmmoRel", PatchType.Prefix);
PatchMethod<PlayerAgent>("GiveDisinfection", PatchType.Prefix);
ChatCommand.RegisterCommand("gr", delegate(string[] parameters)
{
bool giveResourceEnable = ChatCommand.StringToBool(parameters[0]);
EntryPoint.Settings.GiveResourceEnable = giveResourceEnable;
GameEventLogManager.AddLog(string.Format("<color=orange>[MagicRinObserver]</color> <color={0}>" + EntryPoint.Settings.Language.DETECTION_GIVERESOURCE + " {1}</color>", EntryPoint.Settings.GiveResourceEnable ? "green" : "red", EntryPoint.Settings.GiveResourceEnable ? EntryPoint.Settings.Language.ENABLED : EntryPoint.Settings.Language.DISABLED));
}, "[on|off], " + EntryPoint.Settings.Language.ENABLED + "|" + EntryPoint.Settings.Language.DISABLED + " " + EntryPoint.Settings.Language.DETECTION_GIVERESOURCE);
}
private static void PlayerAgent__GiveAmmoRel__Prefix()
{
if (SNet.IsMaster && EntryPoint.Settings.GiveResourceEnable)
{
localGive = true;
}
}
private static void PlayerAgent__GiveDisinfection__Prefix()
{
if (SNet.IsMaster && EntryPoint.Settings.GiveResourceEnable)
{
localGive = true;
}
}
private static void Dam_PlayerDamageBase__ReceiveAddHealth__Prefix(Dam_PlayerDamageBase __instance, pAddHealthData data)
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
if (SNet.IsMaster && EntryPoint.Settings.GiveResourceEnable)
{
OnPreReceiveAddHealth(__instance, data);
}
}
private static void Dam_PlayerDamageBase__ModifyInfection__Prefix(Dam_PlayerDamageBase __instance, pInfection data)
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Invalid comparison between Unknown and I4
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
if (SNet.IsMaster && EntryPoint.Settings.GiveResourceEnable && (int)data.effect == 1)
{
OnPreReceiveModifyInfection(__instance, data);
}
}
private static void PlayerBackpackManager__ReceiveAmmoGive__Prefix(pAmmoGive data)
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
if (SNet.IsMaster && EntryPoint.Settings.GiveResourceEnable)
{
OnPreReceiveAmmoGive(data);
}
}
private static void OnPreReceiveAddHealth(Dam_PlayerDamageBase __instance, pAddHealthData data)
{
SNet_Player val = null;
IReplicator val2 = default(IReplicator);
if (((pReplicator)(ref data.source.pRep)).TryGetID(ref val2))
{
val = val2.OwningPlayer;
}
SNet_Player owner = __instance.Owner.Owner;
if (!(((SFloat16)(ref data.health)).Get(100f) < 20f))
{
string text = ((Object)val).name + ((Object)owner).name + ResourcePackType.Medipack;
if (!alerts.ContainsKey(text))
{
CreateThread(val, owner, ResourcePackType.Medipack, text, add: true);
}
else if (alerts[text].IsAlive)
{
alertsInstance[text].add();
}
else
{
CreateThread(val, owner, ResourcePackType.Medipack, text, add: false);
}
}
}
private static void OnPreReceiveAmmoGive(pAmmoGive data)
{
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
SNet_Player localPlayer = default(SNet_Player);
if (localGive)
{
localPlayer = SNet.LocalPlayer;
}
else
{
SNet.Replication.TryGetLastSender(ref localPlayer, false);
}
localGive = false;
SNet_Player val = default(SNet_Player);
((pPlayer)(ref data.targetPlayer)).GetPlayer(ref val);
ResourcePackType resourcePackType = ((data.ammoClassRel == 0f) ? ResourcePackType.AmmoPack : ResourcePackType.ToolPack);
string text = ((Object)localPlayer).name + ((Object)val).name + resourcePackType;
if (!alerts.ContainsKey(text))
{
CreateThread(localPlayer, val, resourcePackType, text, add: true);
}
else if (alerts[text].IsAlive)
{
alertsInstance[text].add();
}
else
{
CreateThread(localPlayer, val, resourcePackType, text, add: false);
}
}
private static void OnPreReceiveModifyInfection(Dam_PlayerDamageBase __instance, pInfection data)
{
SNet_Player localPlayer = default(SNet_Player);
if (localGive)
{
localPlayer = SNet.LocalPlayer;
}
else
{
SNet.Replication.TryGetLastSender(ref localPlayer, false);
}
localGive = false;
SNet_Player owner = __instance.Owner.Owner;
string text = ((Object)localPlayer).name + ((Object)owner).name + ResourcePackType.DisinfectionPack;
if (!alerts.ContainsKey(text))
{
CreateThread(localPlayer, owner, ResourcePackType.DisinfectionPack, text, add: true);
}
else if (alerts[text].IsAlive)
{
alertsInstance[text].add();
}
else
{
CreateThread(localPlayer, owner, ResourcePackType.DisinfectionPack, text, add: false);
}
}
private static void CreateThread(SNet_Player fromPlayer, SNet_Player toPlayer, ResourcePackType resourcePackType, string threadName, bool add)
{
Timer timer = new Timer();
Thread thread = new Thread((ThreadStart)delegate
{
timer.Start(fromPlayer, toPlayer, resourcePackType);
});
thread.Start();
if (add)
{
alerts.Add(threadName, thread);
alertsInstance.Add(threadName, timer);
}
else
{
alerts[threadName] = thread;
alertsInstance[threadName] = timer;
}
}
}
internal class PlayerJoinLobby : Patch
{
public override string PatchName => "PlayerJoinLobby";
public static PlayerJoinLobby Instance { get; private set; }
public override void Initialize()
{
Instance = this;
}
public override void Execute()
{
PatchMethod<GS_Lobby>("OnPlayerEvent", PatchType.Postfix);
PatchMethod<LocalPlayerAgent>("Setup", PatchType.Postfix);
}
private static void GS_Lobby__OnPlayerEvent__Postfix(SNet_Player player, SNet_PlayerEvent playerEvent)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Invalid comparison between Unknown and I4
if (!player.HasPlayerAgent)
{
return;
}
if ((int)playerEvent != 0)
{
if ((int)playerEvent == 5 && player.IsLocal)
{
UpdateChecker.CheckUpdate();
if (!SNet.IsMaster)
{
GameEventLogManager.AddLog(EntryPoint.Settings.Language.NOT_HOST);
}
else
{
GameEventLogManager.AddLog(EntryPoint.Settings.Language.IS_HOST);
}
}
}
else if (player.IsMaster && !player.IsLocal)
{
if (!SNet.IsMaster)
{
GameEventLogManager.AddLog(EntryPoint.Settings.Language.NOT_HOST);
}
else
{
GameEventLogManager.AddLog(EntryPoint.Settings.Language.IS_HOST);
}
}
}
private static void LocalPlayerAgent__Setup__Postfix()
{
InstallComponents();
}
private static void InstallComponents()
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Expected O, but got Unknown
GameObject val = GameObject.Find("MagicRinObserver");
if ((Object)(object)val == (Object)null)
{
val = new GameObject("MagicRinObserver");
Object.DontDestroyOnLoad((Object)(object)val);
}
if ((Object)(object)val.GetComponent<ChatManager>() == (Object)null)
{
val.AddComponent<ChatManager>();
Logs.LogDebug("已安装组件 ChatManager");
}
if ((Object)(object)val.GetComponent<GameEventLogManager>() == (Object)null)
{
val.AddComponent<GameEventLogManager>();
Logs.LogDebug("已安装组件 GameEventLogManager");
}
}
}
internal class PlayerSlip : Patch
{
public override string PatchName => "PlayerSlip";
public static PlayerSlip Instance { get; private set; }
public override void Initialize()
{
Instance = this;
}
public override void Execute()
{
PatchMethod<Dam_PlayerDamageBase>("ReceiveFallDamage", PatchType.Postfix);
ChatCommand.RegisterCommand("slip", delegate(string[] parameters)
{
bool slipEnable = ChatCommand.StringToBool(parameters[0]);
EntryPoint.Settings.SlipEnable = slipEnable;
GameEventLogManager.AddLog(string.Format("<color=orange>[MagicRinObserver]</color> <color={0}>" + EntryPoint.Settings.Language.DETECTION_PLAYERSLIP + " {1}</color>", EntryPoint.Settings.SlipEnable ? "green" : "red", EntryPoint.Settings.SlipEnable ? EntryPoint.Settings.Language.ENABLED : EntryPoint.Settings.Language.DISABLED));
}, "[on|off], " + EntryPoint.Settings.Language.ENABLED + "|" + EntryPoint.Settings.Language.DISABLED + " " + EntryPoint.Settings.Language.DETECTION_PLAYERSLIP);
}
private static void Dam_PlayerDamageBase__ReceiveFallDamage__Postfix(Dam_PlayerDamageBase __instance, pMiniDamageData data)
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
if (SNet.IsMaster && EntryPoint.Settings.SlipEnable)
{
OnFallDamage(__instance, data);
}
}
private static void OnFallDamage(Dam_PlayerDamageBase __instance, pMiniDamageData data)
{
ChatManager.AddQueueInSeparate(string.Format(EntryPoint.Settings.SlipText, __instance.Owner.Owner.NickName, (int)((UFloat16)(ref data.damage)).Get(100f)));
}
}
internal class PlayerUnderAttack : Patch
{
private static readonly Dictionary<string, Thread> alerts = new Dictionary<string, Thread>();
private static readonly Dictionary<string, Timer> alertsInstance = new Dictionary<string, Timer>();
public override string PatchName => "PlayerUnderAttack";
public static PlayerUnderAttack Instance { get; private set; }
public override void Initialize()
{
Instance = this;
}
public override void Execute()
{
PatchMethod<PouncerBehaviour>("RequestConsume", PatchType.Postfix);
ChatCommand.RegisterCommand("pc", delegate(string[] parameters)
{
bool pouncerConsumeEnable = ChatCommand.StringToBool(parameters[0]);
EntryPoint.Settings.PouncerConsumeEnable = pouncerConsumeEnable;
GameEventLogManager.AddLog(string.Format("<color=orange>[MagicRinObserver]</color> <color={0}>" + EntryPoint.Settings.Language.DETECTION_POUNCERCONSUME + " {1}</color>", EntryPoint.Settings.PouncerConsumeEnable ? "green" : "red", EntryPoint.Settings.PouncerConsumeEnable ? EntryPoint.Settings.Language.ENABLED : EntryPoint.Settings.Language.DISABLED));
}, "[on|off], " + EntryPoint.Settings.Language.ENABLED + "|" + EntryPoint.Settings.Language.DISABLED + " " + EntryPoint.Settings.Language.DETECTION_POUNCERCONSUME);
}
private static void PouncerBehaviour__RequestConsume__Postfix(int playerSlotIndex)
{
if (SNet.IsMaster && EntryPoint.Settings.PouncerConsumeEnable)
{
PlayerAgent val = default(PlayerAgent);
PlayerManager.TryGetPlayerAgent(ref playerSlotIndex, ref val);
ChatManager.AddQueueInSeparate(string.Format(EntryPoint.Settings.PouncerConsumeText, val.Owner.NickName));
}
}
}
internal class SecurityDoorState : Patch
{
private static bool localInteract;
public override string PatchName => "SecurityDoorState";
public static SecurityDoorState Instance { get; private set; }
public override void Initialize()
{
Instance = this;
}
public override void Execute()
{
PatchMethod<LG_Door_Sync>("AttemptDoorInteraction", PatchType.Prefix);
PatchMethod<LG_Door_Sync>("AttemptInteract", PatchType.Prefix);
ChatCommand.RegisterCommand("door", delegate(string[] parameters)
{
bool doorStateEnable = ChatCommand.StringToBool(parameters[0]);
EntryPoint.Settings.DoorStateEnable = doorStateEnable;
GameEventLogManager.AddLog(string.Format("<color=orange>[MagicRinObserver]</color> <color={0}>" + EntryPoint.Settings.Language.DETECTION_DOORSTATE + " {1}</color>", EntryPoint.Settings.DoorStateEnable ? "green" : "red", EntryPoint.Settings.DoorStateEnable ? EntryPoint.Settings.Language.ENABLED : EntryPoint.Settings.Language.DISABLED));
}, "[on|off], " + EntryPoint.Settings.Language.ENABLED + "|" + EntryPoint.Settings.Language.DISABLED + " " + EntryPoint.Settings.Language.DETECTION_DOORSTATE);
}
private static void OnDoorInteract(pDoorInteraction interaction, LG_SecurityDoor door)
{
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Invalid comparison between Unknown and I4
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Invalid comparison between Unknown and I4
SNet_Player localPlayer = default(SNet_Player);
if (localInteract)
{
localPlayer = SNet.LocalPlayer;
}
else
{
SNet.Replication.TryGetLastSender(ref localPlayer, false);
}
string text = door.LinkedToZoneData.Alias.ToString();
eDoorInteractionType type = interaction.type;
if ((int)type != 0)
{
if ((int)type != 4)
{
if ((int)type == 6)
{
if (localInteract || !string.IsNullOrEmpty(localPlayer.NickName))
{
ChatManager.AddQueueInSeparate(string.Format(EntryPoint.Settings.DoorStateSecurityDoorClosedByPlayerText, localPlayer.NickName, text));
}
else
{
ChatManager.AddQueueInSeparate(string.Format(EntryPoint.Settings.DoorStateSecurityDoorClosedText, text));
}
}
}
else if (localInteract || !string.IsNullOrEmpty(localPlayer.NickName))
{
ChatManager.AddQueueInSeparate(string.Format(EntryPoint.Settings.DoorStateSecurityDoorActivatedByPlayerText, localPlayer.NickName, text));
}
else
{
ChatManager.AddQueueInSeparate(string.Format(EntryPoint.Settings.DoorStateSecurityDoorActivatedText, text));
}
}
else if (localInteract || !string.IsNullOrEmpty(localPlayer.NickName))
{
ChatManager.AddQueueInSeparate(string.Format(EntryPoint.Settings.DoorStateSecurityDoorOpenedByPlayerText, localPlayer.NickName, text));
}
else
{
ChatManager.AddQueueInSeparate(string.Format(EntryPoint.Settings.DoorStateSecurityDoorOpenedText, text));
}
localInteract = false;
}
private static void LG_Door_Sync__AttemptDoorInteraction__Prefix(LG_Door_Sync __instance)
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Invalid comparison between Unknown and I4
if (SNet.IsMaster && EntryPoint.Settings.DoorStateEnable && (int)__instance.m_core.DoorType == 2)
{
localInteract = true;
}
}
private static void LG_Door_Sync__AttemptInteract__Prefix(LG_Door_Sync __instance, pDoorInteraction interaction)
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Invalid comparison between Unknown and I4
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
if (SNet.IsMaster && EntryPoint.Settings.DoorStateEnable && (int)__instance.m_core.DoorType == 2)
{
OnDoorInteract(interaction, ((Il2CppObjectBase)__instance.m_core).Cast<LG_SecurityDoor>());
}
}
}
}
namespace Hikaria.MagicRinObserver.Managers
{
internal sealed class ChatManager : MonoBehaviour
{
private readonly Queue<string> queue = new Queue<string>();
public static ChatManager Instance { get; private set; }
private void Awake()
{
Instance = this;
}
private void FixedUpdate()
{
if (queue.Count != 0)
{
lock (queue)
{
Speak(queue.Dequeue());
}
}
}
public static void AddQueueInSeparate(string str, int len = 50)
{
if (len > 50)
{
len = 50;
}
AddQueue(str.SplitByLength(len));
}
public static void AddQueue(string msg)
{
if (msg.Length > 50)
{
AddQueue(msg.SplitByLength(50));
return;
}
lock (Instance.queue)
{
Instance.queue.Enqueue(msg);
}
}
public static void AddQueue(string[] msgs)
{
for (int i = 0; i < msgs.Length; i++)
{
AddQueue(msgs[i]);
}
}
public static void ClearQueue()
{
Instance.queue.Clear();
}
public static void Speak(string text)
{
PlayerChatManager.WantToSentTextMessage(PlayerManager.GetLocalPlayerAgent(), text, (PlayerAgent)null);
}
}
internal sealed class CommandManager
{
private readonly Dictionary<string, Action<string[]>> _commands = new Dictionary<string, Action<string[]>>();
private readonly Dictionary<string, string> _commandHelps = new Dictionary<string, string>();
private string _prefix = string.Empty;
public CommandManager(string prefix)
{
_prefix = prefix.ToLower();
AddCommand("commands", delegate
{
PrintAllCommandHelps();
}, "列出所有可用指令");
AddCommand("help", delegate(string[] parameters)
{
PrintCommandHelp(parameters[0]);
}, "查看指定指令帮助信息");
}
private void PrintAllCommandHelps()
{
GameEventLogManager.AddLog(EntryPoint.Settings.Language.AVAILABLE_COMMANDS);
List<string> list = new List<string>();
foreach (KeyValuePair<string, string> commandHelp in _commandHelps)
{
list.Add($"{_prefix} {commandHelp.Key} {commandHelp.Value}");
}
GameEventLogManager.AddLog(list.ToArray());
}
private void PrintCommandHelp(string key)
{
if (_commandHelps.TryGetValue(key, out var value))
{
GameEventLogManager.AddLog(string.Format(EntryPoint.Settings.Language.COMMAND_HELP, key));
GameEventLogManager.AddLog($"{_prefix} {key} {value}");
}
else if (key != null)
{
GameEventLogManager.AddLog(EntryPoint.Settings.Language.COMMAND_WRONG_INPUT);
}
}
public bool TryExcuteCommand(string key, string[] parameters)
{
try
{
key = key.ToLower();
for (int i = 0; i < parameters.Length; i++)
{
parameters[i] = parameters[i].ToLower();
}
if (_commands.TryGetValue(key, out var value))
{
ExcuteCommand(value, parameters);
return true;
}
}
catch (Exception ex)
{
Logs.LogError(ex.Message);
}
return false;
}
private void ExcuteCommand(Action<string[]> callback, string[] parameters)
{
callback(parameters);
}
public void AddCommand(string key, Action<string[]> callback, string commandHelp)
{
key = key.ToLower();
_commands.Add(key, callback);
_commandHelps.Add(key, commandHelp);
}
}
internal sealed class GameEventLogManager : MonoBehaviour
{
private Queue<string> _gameEventLogs = new Queue<string>();
private float _interval;
public static GameEventLogManager Instance { get; private set; }
private PUI_GameEventLog _playerLayerGameEventLog => GuiManager.PlayerLayer.m_gameEventLog;
private PUI_GameEventLog _pageLoadoutGameEventLog => CM_PageLoadout.Current.m_gameEventLog;
private void Awake()
{
Instance = this;
}
private void FixedUpdate()
{
if (_interval > 0f)
{
_interval -= Time.fixedDeltaTime;
}
else if (_gameEventLogs.Count > 0)
{
string text;
lock (_gameEventLogs)
{
text = _gameEventLogs.Dequeue();
}
_playerLayerGameEventLog.AddLogItem(text, (eGameEventChatLogType)2);
_pageLoadoutGameEventLog.AddLogItem(text, (eGameEventChatLogType)2);
_interval = 0.5f;
}
}
public static void AddLog(string log)
{
lock (Instance._gameEventLogs)
{
Instance._gameEventLogs.Enqueue(log);
}
}
public static void AddLog(string[] logs)
{
for (int i = 0; i < logs.Length; i++)
{
AddLog(logs[i]);
}
}
public static void AddLogInSplit(string str, int len = 50)
{
if (len > 50)
{
len = 50;
}
AddLog(str.SplitByLength(len));
}
}
internal static class ThunderstoreVersionIndex
{
internal static string DecodePayload(byte[] data)
{
if (data == null || data.Length == 0)
{
throw new InvalidDataException("Thunderstore package index payload was empty.");
}
using MemoryStream memoryStream = new MemoryStream(data);
Stream stream = memoryStream;
if (data.Length >= 2 && data[0] == 31 && data[1] == 139)
{
stream = new GZipStream(memoryStream, CompressionMode.Decompress, leaveOpen: false);
}
using (stream)
{
using StreamReader streamReader = new StreamReader(stream, Encoding.UTF8);
return streamReader.ReadToEnd();
}
}
internal static string FindLatestVersion(string json, string packageName)
{
if (string.IsNullOrWhiteSpace(json) || string.IsNullOrWhiteSpace(packageName))
{
return null;
}
using JsonDocument jsonDocument = JsonDocument.Parse(json);
if (jsonDocument.RootElement.ValueKind != JsonValueKind.Array)
{
return null;
}
foreach (JsonElement item in jsonDocument.RootElement.EnumerateArray())
{
if (!item.TryGetProperty("name", out var value) || !string.Equals(value.GetString(), packageName, StringComparison.OrdinalIgnoreCase) || !item.TryGetProperty("versions", out var value2) || value2.ValueKind != JsonValueKind.Array)
{
continue;
}
string text = null;
foreach (JsonElement item2 in value2.EnumerateArray())
{
if (item2.TryGetProperty("version_number", out var value3) && value3.ValueKind == JsonValueKind.String)
{
string text2 = value3.GetString();
if (!string.IsNullOrWhiteSpace(text2) && (text == null || CompareSemanticVersions(text2, text) > 0))
{
text = text2;
}
}
}
return text;
}
return null;
}
internal static int CompareSemanticVersions(string left, string right)
{
SplitVersion(left, out var core, out var prerelease);
SplitVersion(right, out var core2, out var prerelease2);
int num = core.CompareTo(core2);
if (num != 0)
{
return num;
}
if (prerelease == null)
{
if (prerelease2 != null)
{
return 1;
}
return 0;
}
if (prerelease2 == null)
{
return -1;
}
string[] array = prerelease.Split('.');
string[] array2 = prerelease2.Split('.');
int num2 = Math.Min(array.Length, array2.Length);
for (int i = 0; i < num2; i++)
{
int result;
bool flag = int.TryParse(array[i], out result);
int result2;
bool flag2 = int.TryParse(array2[i], out result2);
int num3 = ((flag && flag2) ? result.CompareTo(result2) : ((flag == flag2) ? string.Compare(array[i], array2[i], StringComparison.Ordinal) : ((!flag) ? 1 : (-1))));
if (num3 != 0)
{
return num3;
}
}
return array.Length.CompareTo(array2.Length);
}
private static void SplitVersion(string value, out Version core, out string prerelease)
{
int num = value.IndexOf('+');
string text = ((num < 0) ? value : value.Substring(0, num));
int num2 = text.IndexOf('-');
string input = ((num2 < 0) ? text : text.Substring(0, num2));
prerelease = ((num2 < 0) ? null : text.Substring(num2 + 1));
if (!Version.TryParse(input, out core))
{
core = new Version(0, 0, 0, 0);
}
}
}
internal static class TranslateManager
{
[Serializable]
public struct EnemyNameID
{
public List<uint> IDs;
public string Name;
}
private static readonly Dictionary<uint, string> EnemyID2Name = new Dictionary<uint, string>();
private static readonly string CONFIG_ENEMYNAMEID = Paths.ConfigPath + "\\MagicRinObserver\\EnemyNameIDs.json";
public static string EnemyName(uint id)
{
if (EnemyID2Name.TryGetValue(id, out var value))
{
return value;
}
Logs.LogMessage($"Unknown Enemy ID: {id}, Name: {((GameDataBlockBase<EnemyDataBlock>)(object)GameDataBlockBase<EnemyDataBlock>.GetBlock(id)).name}");
return ((GameDataBlockBase<EnemyDataBlock>)(object)GameDataBlockBase<EnemyDataBlock>.GetBlock(id)).name;
}
public static void Init()
{
LoadFromDisk();
}
private static void LoadFromDisk()
{
EnemyID2Name.Clear();
new Hikaria.MagicRinObserver.Utils.JsonConverter().TryRead<List<EnemyNameID>>(CONFIG_ENEMYNAMEID, out var output);
foreach (EnemyNameID item in output)
{
foreach (uint iD in item.IDs)
{
EnemyID2Name.Add(iD, item.Name);
}
}
}
}
internal static class UpdateChecker
{
private const string PackageIndexUrl = "https://thunderstore.io/c/gtfo/api/v1/package-listing-index/";
private const string ThunderstoreHomeUrl = "https://thunderstore.io/c/gtfo/";
private static bool _checkStarted;
public static void CheckUpdate()
{
if (!_checkStarted)
{
_checkStarted = true;
GameEventLogManager.AddLog(string.Format(EntryPoint.Settings.Language.CURRENT_VERSION, "1.0.0"));
GameEventLogManager.AddLog(EntryPoint.Settings.Language.CHECKING_UPDATE);
HttpHelper.Get("https://thunderstore.io/c/gtfo/api/v1/package-listing-index/", ReadPackageIndexUrl, HandleRequestFailure);
}
}
private static void ReadPackageIndexUrl(UnityWebRequest request)
{
try
{
using JsonDocument jsonDocument = JsonDocument.Parse(ThunderstoreVersionIndex.DecodePayload(Il2CppArrayBase<byte>.op_Implicit((Il2CppArrayBase<byte>)(object)request.downloadHandler.data)));
JsonElement rootElement = jsonDocument.RootElement;
if (rootElement.ValueKind != JsonValueKind.Array || rootElement.GetArrayLength() == 0)
{
throw new InvalidDataException("Thunderstore package index did not return a blob URL.");
}
if (!Uri.TryCreate(rootElement[0].GetString(), UriKind.Absolute, out Uri result) || result.Scheme != Uri.UriSchemeHttps)
{
throw new InvalidDataException("Thunderstore package index returned an invalid blob URL.");
}
HttpHelper.Get(result.AbsoluteUri, ReadPackageVersions, HandleRequestFailure);
}
catch (Exception ex)
{
HandleCheckFailure(ex.Message);
}
}
private static void ReadPackageVersions(UnityWebRequest request)
{
try
{
string text = ThunderstoreVersionIndex.FindLatestVersion(ThunderstoreVersionIndex.DecodePayload(Il2CppArrayBase<byte>.op_Implicit((Il2CppArrayBase<byte>)(object)request.downloadHandler.data)), "MagicRinObserverCompat");
if (text == null)
{
HandleCheckFailure("Package 'MagicRinObserverCompat' is not present in the GTFO package index.");
return;
}
if (ThunderstoreVersionIndex.CompareSemanticVersions(text, "1.0.0") > 0)
{
string arg = "查看 Thunderstore 页面:https://thunderstore.io/c/gtfo/";
GameEventLogManager.AddLog(string.Format(EntryPoint.Settings.Language.DETECT_LATER_VERSION, text, arg).Split('\\'));
}
else
{
GameEventLogManager.AddLog(EntryPoint.Settings.Language.IS_LATEST_VERSION);
}
GameEventLogManager.AddLog(EntryPoint.Settings.Language.COMMAND_LIST);
}
catch (Exception ex)
{
HandleCheckFailure(ex.Message);
}
}
private static void HandleRequestFailure(UnityWebRequest request)
{
HandleCheckFailure((request == null) ? "HTTP request failed." : request.error);
}
private static void HandleCheckFailure(string reason)
{
Logs.LogError("检查 Thunderstore 更新失败: " + reason);
GameEventLogManager.AddLog(EntryPoint.Settings.Language.CHECK_UPDATE_FAILD);
GameEventLogManager.AddLog(EntryPoint.Settings.Language.COMMAND_LIST);
}
}
}
namespace Hikaria.MagicRinObserver.Lang
{
internal class English : LanguageBase
{
public override string AVAILABLE_COMMANDS => "<color=orange>[MagicRinObserver]</color> Command list:";
public override string SETTINGS_CHECK => "<color=orange>[MagicRinObserver]</color> Current settings:";
public override string COMMAND_LIST => "<color=orange>[MagicRinObserver]</color> Enter '/magicrin commands' to list all commands";
public override string COMMAND_HELP => "<color=orange>[MagicRinObserver]</color> Command {0} help info:";
public override string COMMAND_WRONG_INPUT => "<color=orange>[MagicRinObserver]</color> <color=red>Wrong input!</color>";
public override string CURRENT_VERSION => "<color=orange>[MagicRinObserver]</color> Build: v{0}";
public override string CHECKING_UPDATE => "<color=orange>[MagicRinObserver]</color> Checking for updates...";
public override string IS_LATEST_VERSION => "<color=orange>[MagicRinObserver]</color> <color=green>The current version is already the latest.</color>";
public override string CHECK_UPDATE_FAILD => "<color=orange>[MagicRinObserver]</color> <color=red>Check for updates failed.</color>";
public override string DETECT_LATER_VERSION => "<color=orange>[MagicRinObserver]</color> <color=green>New version: </color><color=orange>v{0}</color>\\<color=orange>[MagicRinObserver]</color> Changelog: \\{1}";
public override string LOADED => "MagicRinObserver Loaded";
public override string IGNORE_REPEAT_PATCH => "Ignoring duplicate patch: {0}";
public override string PATCHING => "Applying patch: {0}";
public override string NOT_HOST => "<color=orange>[MagicRinObserver]</color> <color=red>The mod will not function since you are not the host.</color>";
public override string IS_HOST => "<color=orange>[MagicRinObserver]</color> <color=green>The mod will function since you are the host.</color>";
public override string SELF => "self";
public override string TOOL => "tool";
public override string WEAPON => "weapon";
public override string ENABLED => "enabled";
public override string DISABLED => "disabled";
public override string DETECTION_ENEMYWAKEUP => "Enemy wakeup detection";
public override string DETECTION_PLAYERSLIP => "Player slip detection";
public override string DETECTION_FRIENDLYFIRE => "Friendly fire detection";
public override string DETECTION_GIVERESOURCE => "Give resource detection";
public override string DETECTION_POUNCERCONSUME => "Pouncer consume detection";
public override string DETECTION_KILLTIMER => "Kill timer";
public override string DETECTION_DOORSTATE => "Security door state detection";
}
public abstract class LanguageBase
{
public abstract string AVAILABLE_COMMANDS { get; }
public abstract string COMMAND_LIST { get; }
public abstract string COMMAND_HELP { get; }
public abstract string COMMAND_WRONG_INPUT { get; }
public abstract string SETTINGS_CHECK { get; }
public abstract string CURRENT_VERSION { get; }
public abstract string CHECKING_UPDATE { get; }
public abstract string IS_LATEST_VERSION { get; }
public abstract string CHECK_UPDATE_FAILD { get; }
public abstract string DETECT_LATER_VERSION { get; }
public abstract string LOADED { get; }
public abstract string IGNORE_REPEAT_PATCH { get; }
public abstract string NOT_HOST { get; }
public abstract string IS_HOST { get; }
public abstract string PATCHING { get; }
public abstract string SELF { get; }
public abstract string TOOL { get; }
public abstract string WEAPON { get; }
public abstract string ENABLED { get; }
public abstract string DISABLED { get; }
public abstract string DETECTION_ENEMYWAKEUP { get; }
public abstract string DETECTION_PLAYERSLIP { get; }
public abstract string DETECTION_FRIENDLYFIRE { get; }
public abstract string DETECTION_GIVERESOURCE { get; }
public abstract string DETECTION_POUNCERCONSUME { get; }
public abstract string DETECTION_KILLTIMER { get; }
public abstract string DETECTION_DOORSTATE { get; }
}
internal class SimplifiedChinese : LanguageBase
{
public override string AVAILABLE_COMMANDS => "<color=orange>[MagicRinObserver]</color> 可用指令如下:";
public override string SETTINGS_CHECK => "<color=orange>[MagicRinObserver]</color> 当前设置:";
public override string COMMAND_LIST => "<color=orange>[MagicRinObserver]</color> 输入 '/magicrin commonds' 可查看所有指令";
public override string COMMAND_HELP => "<color=orange>[MagicRinObserver]</color> 指令 {0} 帮助信息:";
public override string COMMAND_WRONG_INPUT => "<color=orange>[MagicRinObserver]</color> <color=red>输入有误!</color>";
public override string CURRENT_VERSION => "<color=orange>[MagicRinObserver]</color> 当前版本: v{0}";
public override string CHECKING_UPDATE => "<color=orange>[MagicRinObserver]</color> 正在检查更新...";
public override string IS_LATEST_VERSION => "<color=orange>[MagicRinObserver]</color> <color=green>当前已是最新版本</color>";
public override string CHECK_UPDATE_FAILD => "<color=orange>[MagicRinObserver]</color> <color=red>检查更新失败!</color>";
public override string DETECT_LATER_VERSION => "<color=orange>[MagicRinObserver]</color> <color=green>发现新版本: </color><color=orange>v{0}</color>\\<color=orange>[MagicRinObserver]</color> 更新日志: \\{1}";
public override string LOADED => "MagicRinObserver 已加载";
public override string IGNORE_REPEAT_PATCH => "忽略重复的补丁: {0}";
public override string PATCHING => "正在应用补丁: {0}";
public override string NOT_HOST => "<color=orange>[MagicRinObserver]</color> <color=red>你当前不是房主,将无法使用本mod功能</color>";
public override string IS_HOST => "<color=orange>[MagicRinObserver]</color> <color=green>你当前是房主,可以使用本mod功能</color>";
public override string SELF => "自己";
public override string TOOL => "工具";
public override string WEAPON => "武器";
public override string ENABLED => "启用";
public override string DISABLED => "禁用";
public override string DETECTION_ENEMYWAKEUP => "敌人惊醒检测";
public override string DETECTION_PLAYERSLIP => "玩家跌落伤害检测";
public override string DETECTION_FRIENDLYFIRE => "队友伤害检测";
public override string DETECTION_GIVERESOURCE => "资源使用检测";
public override string DETECTION_POUNCERCONSUME => "狗吞玩家检测";
public override string DETECTION_KILLTIMER => "敌人击杀计时";
public override string DETECTION_DOORSTATE => "安全门状态检测";
}
}
namespace Hikaria.MagicRinObserver.Ext
{
internal static class StringExt
{
public static string[] SplitByLength(this string str, int length)
{
List<string> list = new List<string>();
for (int i = 0; i < str.Length; i += length)
{
int length2 = Math.Min(length, str.Length - i);
string item = str.Substring(i, length2);
list.Add(item);
}
return list.ToArray();
}
}
}
namespace Hikaria.MagicRinObserver.Config
{
internal class ConfigDescription
{
internal static string FRIENDLY_FIRE_DESC => "默认[开启|关闭]队友伤害提示功能,接受的值:[true|false]";
internal static string LANGUAGE_DESC => "切换mod显示语言,接受的值:[en_US|zh_CN]";
internal static string SETTINGS_COMMON => "通用设置";
internal static string SETTINGS_DOOR => "安全门设置";
internal static string SETTINGS_PLAYERUNDERATTACK => "玩家受到攻击设置";
internal static string SETTINGS_PLAYERSLIP => "玩家摔倒设置";
internal static string SETTINGS_GIVERESOURCE => "资源使用设置";
internal static string SETTINGS_ENEMYWAKEUP => "敌人惊醒设置";
internal static string SETTINGS_FRIENDLYFIRE => "队友伤害设置";
internal static string SETTINGS_ENEMYUNDERATTACK => "敌人受到伤害设置";
internal static string FRIENDLY_FIRE_NAME => "FriendlyFire";
internal static string LANGUAGE_NAME => "Language";
internal static string ENEMYWAKEUP_DESC => "默认[开启|关闭]敌人惊醒提示功能,接受的值:[true|false]";
internal static string ENEMYWAKEUP_NAME => "EnemyWakeup";
internal static string ENEMYWAKEUP_TEXT_NAME => "EnemyWakeupText";
internal static string ENEMYWAKEUP_TEXT_DESC => "自定义敌人惊醒检测的提示语句,{0}为玩家名字,{1}为敌人数量,{2}为敌人名称";
internal static string SLIP_NAME => "PlayerSlip";
internal static string SLIP_DESC => "默认[开启|关闭]玩家跌落伤害检测提示功能,接受的值:[true|false]";
internal static string SLIP_TEXT_NAME => "PlayerSlipText";
internal static string SLIP_TEXT_DESC => "自定义玩家跌落伤害检测的提示语句,{0}为玩家名字,{1}为损失的血量";
internal static string GIVERESOURCE_NAME => "GiveResource";
internal static string GIVERESOURCE_DESC => "默认[开启|关闭]资源使用检测提示功能,接受的值:[true|false]";
internal static string GIVERESOURCE_HEALTH_TEXT_DESC => "自定义医疗包使用检测的提示语句,{0}为提供者名字,{1}为接受者名字,{2}为使用医疗包次数";
internal static string GIVERESOURCE_AMMO_TEXT_DESC => "自定义弹药包使用检测的提示语句,{0}为提供者名字,{1}为接受者名字,{2}为使用弹药包次数,{3}为弹药包种类";
internal static string GIVERESOURCE_DISINFECTION_TEXT_DESC => "自定义消毒剂使用检测的提示语句,{0}为提供者名字,{1}为接受者名字,{2}为使用消毒剂次数";
internal static string GIVERESOURCE_AMMO_NAME => "GiveResourceAmmoText";
internal static string GIVERESOURCE_HEALTH_NAME => "GiveResourceHealthText";
internal static string GIVERESOURCE_DISINFECTION_NAME => "GiveResourceDisinfectionText";
internal static string FRIENDLY_FIRE_BULLET_TEXT_DESC => "自定义黑枪的提示语句,{0}为黑枪者名字,{1}为被黑者名字,{2}为黑枪次数,{3}为损失的血量";
internal static string FRIENDLY_FIRE_BULLET_TEXT_NAME => "FriendlyFireBulletText";
internal static string FRIENDLY_FIRE_EXPLOSION_TEXT_NAME => "FriendlyFireExplosionText";
internal static string FRIEDNLU_FIRE_EXPLOSION_TEXT_DESC => "自定义拌雷误伤的提示语句,{0}为被炸者名字,{1}为损失的血量";
internal static string POUNCERCONSUME_NAME => "PouncerConsume";
internal static string POUNCERCONSUME_TEXT_NAME => "PouncerConsumeText";
internal static string POUNCERCONSUME_TEXT_DESC => "自定义狗吞玩家检测的提示语句,{0}为玩家名字";
internal static string POUNCERCONSUME_DESC => "默认[开启|关闭]狗吞玩家检测提示功能,接受的值:[true|false]";
internal static string ENEMYUNDERATTACKKILLTIMER_TEXT_NAME => "EnemyUnderAttackKillTimerText";
internal static string ENEMYUNDERATTACKKILLTIMER_TEXT_DESC => "自定义击杀敌人计时的提示语句,{0}为敌人种类,{1}为击杀耗时";
internal static string DOORSTATE_DESC => "默认[开启|关闭]安全门状态检测提示功能,接受的值:[true|false]";
internal static string DOORSTATE_NAME => "DoorState";
internal static string DOORSTATESECURITYDOOROPENED_TEXT_NAME => "DoorStateSecurityDoorOpenedText";
internal static string DOORSTATESECURITYDOOROPENED_TEXT_DESC => "自定义安全门开启检测的提示语句";
internal static string DOORSTATESECURITYDOORCLOSED_TEXT_DESC => "自定义安全门关闭检测的提示语句";
internal static string DOORSTATESECURITYDOORCLOSED_TEXT_NAME => "DoorStateSecurityDoorClosedText";
internal static string DOORSTATESECURITYDOORACTIVATED_TEXT_NAME => "DoorStateSecurityDoorActivatedText";
internal static string DOORSTATESECURITYDOORACTIVATED_TEXT_DESC => "自定义安全门激活检测的提示语句";
internal static string DOORSTATESECURITYDOOROPENEDBYPLAYER_TEXT_DESC => "自定义安全门被玩家开启检测的提示语句";
internal static string DOORSTATESECURITYDOOROPENEDBYPLAYER_TEXT_NAME => "DoorStateSecurityDoorOpenedByPlayerText";
internal static string DOORSTATESECURITYDOORCLOSEDBYPLAYER_TEXT_DESC => "自定义安全门被玩家关闭检测的提示语句";
internal static string DOORSTATESECURITYDOORCLOSEDBYPLAYER_TEXT_NAME => "DoorStateSecurityDoorClosedByPlayerText";
internal static string DOORSTATESECURITYDOORACTIVATEDBYPLAYER_TEXT_NAME => "DoorStateSecurityDoorActivatedByPlayerText";
internal static string DOORSTATESECURITYDOORACTIVATEDBYPLAYER_TEXT_DESC => "自定义安全门被玩家激活检测的提示语句";
internal static string ENEMYUNDERATTACKKILLTIMER_NAME => "EnemyUnderAttackKillTimer";
internal static string ENEMYUNDERATTACKKILLTIMER_DESC => "默认[开启|关闭]击杀敌人计时提示功能,接受的值:[true|false]";
}
internal class ConfigManager
{
public enum Language : byte
{
en_US,
zh_CN
}
public static ConfigEntry<bool> enemyWakeup;
public static ConfigEntry<string> enemyWakeup_text;
public static ConfigEntry<bool> firendlyFire;
public static ConfigEntry<Language> language;
public static ConfigEntry<bool> playerSlip;
public static ConfigEntry<string> playerSlip_text;
public static ConfigEntry<bool> giveResource;
public static ConfigEntry<string> giveResourceHealth_text;
public static ConfigEntry<string> giveResourceAmmo_text;
public static ConfigEntry<string> giveResourceDisinfection_text;
public static ConfigEntry<string> friendlyFire_text;
public static ConfigEntry<string> friendlyFire_Explosion_text;
public static ConfigEntry<string> giveResourceHealthSelf_text;
public static ConfigEntry<bool> pouncerConsume;
public static ConfigEntry<string> pouncerConsume_text;
public static ConfigEntry<bool> playerUnderAttack;
public static ConfigEntry<string> playerUnderAttackTentacle_text;
public static ConfigEntry<string> playerUnderAttackShooterProjectile_text;
public static ConfigEntry<string> playerUnderAttackMelee_text;
public static ConfigEntry<string> playerUnderAttackParasite_text;
public static ConfigEntry<string> enemyUnderAttackInstantKillSuccessfully_text;
public static ConfigEntry<string> enemyUnderAttackKillInSecFailed_text;
public static ConfigEntry<string> enemyUnderAttackKillTimer_text;
public static ConfigEntry<string> enemyUnderAttackKillInSecSuccessfully_text;
public static ConfigEntry<string> doorStateSecurityDoorOpened_text;
public static ConfigEntry<string> doorStateSecurityDoorOpenedByPlayer_text;
public static ConfigEntry<string> doorStateSecurityDoorActivated_text;
public static ConfigEntry<string> doorStateSecurityDoorActivatedByPlayer_text;
public static ConfigEntry<string> doorStateSecurityDoorClosed_text;
public static ConfigEntry<string> doorStateSecurityDoorClosedByPlayer_text;
public static ConfigEntry<bool> doorState;
public static ConfigEntry<bool> enemyUnderAttackInstantKill;
public static ConfigEntry<bool> enemyUnderAttackKillTimer;
static ConfigManager()
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: 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)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
//IL_00f7: 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_013f: Unknown result type (might be due to invalid IL or missing references)
//IL_0163: Unknown result type (might be due to invalid IL or missing references)
//IL_017e: Unknown result type (might be due to invalid IL or missing references)
//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
//IL_0205: Unknown result type (might be due to invalid IL or missing references)
//IL_0229: Unknown result type (might be due to invalid IL or missing references)
//IL_024d: Unknown result type (might be due to invalid IL or missing references)
//IL_0271: Unknown result type (might be due to invalid IL or missing references)
//IL_0295: Unknown result type (might be due to invalid IL or missing references)
//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
Logs.LogDebug("正在加载配置文件...");
ConfigFile val = new ConfigFile(Paths.ConfigPath + "\\MagicRinObserver\\MagicRinObserver.cfg", true);
language = val.Bind<Language>(ConfigDescription.SETTINGS_COMMON, ConfigDescription.LANGUAGE_NAME, Language.zh_CN, ConfigDescription.LANGUAGE_DESC);
enemyWakeup = val.Bind<bool>(ConfigDescription.SETTINGS_ENEMYWAKEUP, ConfigDescription.ENEMYWAKEUP_NAME, true, ConfigDescription.ENEMYWAKEUP_DESC);
enemyWakeup_text = val.Bind<string>(ConfigDescription.SETTINGS_ENEMYWAKEUP, ConfigDescription.ENEMYWAKEUP_TEXT_NAME, EntryPoint.Settings.EnemyWakeupText, ConfigDescription.ENEMYWAKEUP_TEXT_DESC);
firendlyFire = val.Bind<bool>(ConfigDescription.SETTINGS_FRIENDLYFIRE, ConfigDescription.FRIENDLY_FIRE_NAME, true, ConfigDescription.FRIENDLY_FIRE_DESC);
friendlyFire_text = val.Bind<string>(ConfigDescription.SETTINGS_FRIENDLYFIRE, ConfigDescription.FRIENDLY_FIRE_BULLET_TEXT_NAME, EntryPoint.Settings.FriendlyFireText, ConfigDescription.FRIENDLY_FIRE_BULLET_TEXT_DESC);
friendlyFire_Explosion_text = val.Bind<string>(ConfigDescription.SETTINGS_FRIENDLYFIRE, ConfigDescription.FRIENDLY_FIRE_EXPLOSION_TEXT_NAME, EntryPoint.Settings.FriendlyFireExplosionText, ConfigDescription.FRIEDNLU_FIRE_EXPLOSION_TEXT_DESC);
giveResource = val.Bind<bool>(ConfigDescription.SETTINGS_GIVERESOURCE, ConfigDescription.GIVERESOURCE_NAME, true, ConfigDescription.GIVERESOURCE_DESC);
giveResourceHealth_text = val.Bind<string>(ConfigDescription.SETTINGS_GIVERESOURCE, ConfigDescription.GIVERESOURCE_HEALTH_NAME, EntryPoint.Settings.GiveResourceHealthText, ConfigDescription.GIVERESOURCE_HEALTH_TEXT_DESC);
giveResourceAmmo_text = val.Bind<string>(ConfigDescription.SETTINGS_GIVERESOURCE, ConfigDescription.GIVERESOURCE_AMMO_NAME, EntryPoint.Settings.GiveResourceAmmoText, ConfigDescription.GIVERESOURCE_AMMO_TEXT_DESC);
giveResourceDisinfection_text = val.Bind<string>(ConfigDescription.SETTINGS_GIVERESOURCE, ConfigDescription.GIVERESOURCE_DISINFECTION_NAME, EntryPoint.Settings.GiveResourceDisinfectionText, ConfigDescription.GIVERESOURCE_DISINFECTION_TEXT_DESC);
playerSlip = val.Bind<bool>(ConfigDescription.SETTINGS_PLAYERSLIP, ConfigDescription.SLIP_NAME, true, ConfigDescription.SLIP_DESC);
playerSlip_text = val.Bind<string>(ConfigDescription.SETTINGS_PLAYERSLIP, ConfigDescription.SLIP_TEXT_NAME, EntryPoint.Settings.SlipText, ConfigDescription.SLIP_TEXT_DESC);
pouncerConsume = val.Bind<bool>(ConfigDescription.SETTINGS_PLAYERUNDERATTACK, ConfigDescription.POUNCERCONSUME_NAME, true, ConfigDescription.POUNCERCONSUME_DESC);
pouncerConsume_text = val.Bind<string>(ConfigDescription.SETTINGS_PLAYERUNDERATTACK, ConfigDescription.POUNCERCONSUME_TEXT_NAME, EntryPoint.Settings.PouncerConsumeText, ConfigDescription.POUNCERCONSUME_TEXT_DESC);
enemyUnderAttackKillTimer = val.Bind<bool>(ConfigDescription.SETTINGS_ENEMYUNDERATTACK, ConfigDescription.ENEMYUNDERATTACKKILLTIMER_NAME, EntryPoint.Settings.EnemyUnderAttackKillTimerEnable, ConfigDescription.ENEMYUNDERATTACKKILLTIMER_DESC);
enemyUnderAttackKillTimer_text = val.Bind<string>(ConfigDescription.SETTINGS_ENEMYUNDERATTACK, ConfigDescription.ENEMYUNDERATTACKKILLTIMER_TEXT_NAME, EntryPoint.Settings.EnemyUnderAttackKillTimerText, ConfigDescription.ENEMYUNDERATTACKKILLTIMER_TEXT_DESC);
doorState = val.Bind<bool>(ConfigDescription.SETTINGS_DOOR, ConfigDescription.DOORSTATE_NAME, EntryPoint.Settings.DoorStateEnable, ConfigDescription.DOORSTATE_DESC);
doorStateSecurityDoorOpened_text = val.Bind<string>(ConfigDescription.SETTINGS_DOOR, ConfigDescription.DOORSTATESECURITYDOOROPENED_TEXT_NAME, EntryPoint.Settings.DoorStateSecurityDoorOpenedText, ConfigDescription.DOORSTATESECURITYDOOROPENED_TEXT_DESC);
doorStateSecurityDoorClosed_text = val.Bind<string>(ConfigDescription.SETTINGS_DOOR, ConfigDescription.DOORSTATESECURITYDOORCLOSED_TEXT_NAME, EntryPoint.Settings.DoorStateSecurityDoorClosedText, ConfigDescription.DOORSTATESECURITYDOORCLOSED_TEXT_DESC);
doorStateSecurityDoorActivated_text = val.Bind<string>(ConfigDescription.SETTINGS_DOOR, ConfigDescription.DOORSTATESECURITYDOORACTIVATED_TEXT_NAME, EntryPoint.Settings.DoorStateSecurityDoorActivatedText, ConfigDescription.DOORSTATESECURITYDOORACTIVATED_TEXT_DESC);
doorStateSecurityDoorOpenedByPlayer_text = val.Bind<string>(ConfigDescription.SETTINGS_DOOR, ConfigDescription.DOORSTATESECURITYDOOROPENEDBYPLAYER_TEXT_NAME, EntryPoint.Settings.DoorStateSecurityDoorOpenedByPlayerText, ConfigDescription.DOORSTATESECURITYDOOROPENEDBYPLAYER_TEXT_DESC);
doorStateSecurityDoorClosedByPlayer_text = val.Bind<string>(ConfigDescription.SETTINGS_DOOR, ConfigDescription.DOORSTATESECURITYDOORCLOSEDBYPLAYER_TEXT_NAME, EntryPoint.Settings.DoorStateSecurityDoorClosedByPlayerText, ConfigDescription.DOORSTATESECURITYDOORCLOSEDBYPLAYER_TEXT_DESC);
doorStateSecurityDoorActivatedByPlayer_text = val.Bind<string>(ConfigDescription.SETTINGS_DOOR, ConfigDescription.DOORSTATESECURITYDOORACTIVATEDBYPLAYER_TEXT_NAME, EntryPoint.Settings.DoorStateSecurityDoorActivatedByPlayerText, ConfigDescription.DOORSTATESECURITYDOORACTIVATEDBYPLAYER_TEXT_DESC);
Logs.LogDebug("配置文件加载完成");
}
public bool GetEnemyWakeup()
{
return enemyWakeup.Value;
}
public string GetEnemyWakeupText()
{
return enemyWakeup_text.Value;
}
public bool GetFriendlyFire()
{
return firendlyFire.Value;
}
public bool GetPlayerSlip()
{
return playerSlip.Value;
}
public string GetSlipText()
{
return playerSlip_text.Value;
}
public LanguageBase GetLanguage()
{
if (language.Value == Language.en_US)
{
return new English();
}
return new SimplifiedChinese();
}
public Language GetLanguageName()
{
return language.Value;
}
public bool GetGiveResource()
{
return giveResource.Value;
}
public string GetGiveResourceHealthText()
{
return giveResourceHealth_text.Value;
}
public string GetGiveResourceAmmoText()
{
return giveResourceAmmo_text.Value;
}
public string GetGiveResourceDisinfectionText()
{
return giveResourceDisinfection_text.Value;
}
public string GetFriendlyFireText()
{
return friendlyFire_text.Value;
}
public string GetFirendFireExplosionText()
{
return friendlyFire_Explosion_text.Value;
}
public string GetGiveResourceHealthSelfText()
{
return giveResourceHealthSelf_text.Value;
}
public string GetPouncerConsumeText()
{
return pouncerConsume_text.Value;
}
public bool GetPouncerConsume()
{
return pouncerConsume.Value;
}
public bool GetPlayerUnderAttack()
{
return playerUnderAttack.Value;
}
public string GetPlayerUnderAttackTentacleText()
{
return playerUnderAttackTentacle_text.Value;
}
public string GetPlayerUnderAttackShooterProjectileText()
{
return playerUnderAttackShooterProjectile_text.Value;
}
public string GetPlayerUnderAttackMeleeText()
{
return playerUnderAttackMelee_text.Value;
}
public string GetPlayerUnderAttackParasiteText()
{
return playerUnderAttackParasite_text.Value;
}
public bool GetEnemyUnderAttackInstantKill()
{
return enemyUnderAttackInstantKill.Value;
}
public bool GetEnemyUnderAttackKillTimer()
{
return enemyUnderAttackKillTimer.Value;
}
public string GetEnemyUnderAttackInstantKillSuccessfullyTest()
{
return enemyUnderAttackInstantKillSuccessfully_text.Value;
}
public string GetEnemyUnderAttackKillInSecFailedText()
{
return enemyUnderAttackKillInSecFailed_text.Value;
}
public string GetEnemyUnderAttackKillInSecSuccessfullyText()
{
return enemyUnderAttackKillInSecSuccessfully_text.Value;
}
public bool GetDoorStateSecurityDoorOpen()
{
return doorState.Value;
}
public string GetDoorStateSecurityDoorOpenedText()
{
return doorStateSecurityDoorOpened_text.Value;
}
public string GetDoorStateSecurityDoorActivatedText()
{
return doorStateSecurityDoorActivated_text.Value;
}
public string GetDoorStateSecurityDoorClosedText()
{
return doorStateSecurityDoorClosed_text.Value;
}
public string GetDoorStateSecurityDoorOpenedByPlayerText()
{
return doorStateSecurityDoorOpenedByPlayer_text.Value;
}
public string GetDoorStateSecurityDoorActivatedByPlayerText()
{
return doorStateSecurityDoorActivatedByPlayer_text.Value;
}
public string GetDoorStateSecurityDoorClosedByPlayerText()
{
return doorStateSecurityDoorClosedByPlayer_text.Value;
}
public string GetEnemyUnderAttackKillTimerText()
{
return enemyUnderAttackKillTimer_text.Value;
}
}
internal class Settings
{
public bool EnemyWakeupEnable = true;
public string EnemyWakeupText = "{0} 惊醒了 {1} 只 {2}";
public bool FriendlyFireEnable = true;
public bool SlipEnable = true;
public string SlipText = "{0} 摔了一跤,HP-{1}%";
public LanguageBase Language;
public ConfigManager.Language LanguageName = ConfigManager.Language.zh_CN;
public bool GiveResourceEnable = true;
public string FriendlyFireText = "{0} 黑了 {1} 共 {2} 枪,HP-{3}%";
public string GiveResourceHealthText = "{0} 对 {1} 使用了 {2} 次 医疗包";
public string GiveResourceAmmoText = "{0} 对 {1} 使用了 {2} 次 {3}弹药包";
public string GiveResourceDisinfectionText = "{0} 对 {1} 使用了 {2} 次 消毒剂";
public string FriendlyFireExplosionText = "{0} 受到爆炸伤害,HP-{1}%";
public string PouncerConsumeText = "{0} 被狗吞了";
public bool PouncerConsumeEnable = true;
public bool DoorStateEnable = true;
public string EnemyUnderAttackKillInSecFailedText = "{0} 秒杀 {1} 失败";
public bool EnemyUnderAttackInstantKillEnable = true;
public bool EnemyUnderAttackKillTimerEnable = true;
public string EnemyUnderAttackKillTimerText = "击杀 {0} 总计耗时 {1}s";
public string DoorStateSecurityDoorOpenedText = "ZONE_{0} 安全门已开启";
public string DoorStateSecurityDoorActivatedText = "ZONE_{0} 安全门已激活";
public string DoorStateSecurityDoorClosedText = "ZONE_{0} 安全门已关闭";
public string DoorStateSecurityDoorOpenedByPlayerText = "{0} 开启了 ZONE_{1} 安全门";
public string DoorStateSecurityDoorActivatedByPlayerText = "{0} 激活了 ZONE_{1} 安全门";
public string DoorStateSecurityDoorClosedByPlayerText = "{0} 关闭了 ZONE_{1} 安全门";
public void Setup()
{
ConfigManager configManager = new ConfigManager();
EnemyWakeupEnable = configManager.GetEnemyWakeup();
EnemyWakeupText = configManager.GetEnemyWakeupText();
SlipEnable = configManager.GetPlayerSlip();
SlipText = configManager.GetSlipText();
FriendlyFireEnable = configManager.GetFriendlyFire();
FriendlyFireText = configManager.GetFriendlyFireText();
FriendlyFireExplosionText = configManager.GetFirendFireExplosionText();
GiveResourceEnable = configManager.GetGiveResource();
GiveResourceHealthText = configManager.GetGiveResourceHealthText();
GiveResourceDisinfectionText = configManager.GetGiveResourceDisinfectionText();
GiveResourceAmmoText = configManager.GetGiveResourceAmmoText();
PouncerConsumeEnable = configManager.GetPouncerConsume();
PouncerConsumeText = configManager.GetPouncerConsumeText();
DoorStateEnable = configManager.GetDoorStateSecurityDoorOpen();
DoorStateSecurityDoorOpenedText = configManager.GetDoorStateSecurityDoorOpenedText();
DoorStateSecurityDoorClosedText = configManager.GetDoorStateSecurityDoorClosedText();
DoorStateSecurityDoorActivatedText = configManager.GetDoorStateSecurityDoorActivatedText();
DoorStateSecurityDoorOpenedByPlayerText = configManager.GetDoorStateSecurityDoorOpenedByPlayerText();
DoorStateSecurityDoorClosedByPlayerText = configManager.GetDoorStateSecurityDoorClosedByPlayerText();
DoorStateSecurityDoorActivatedByPlayerText = configManager.GetDoorStateSecurityDoorActivatedByPlayerText();
EnemyUnderAttackKillTimerEnable = configManager.GetEnemyUnderAttackKillTimer();
EnemyUnderAttackKillTimerText = configManager.GetEnemyUnderAttackKillTimerText();
Language = configManager.GetLanguage();
LanguageName = configManager.GetLanguageName();
}
}
}