using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using LLBML.GameEvents;
using LLBML.Messages;
using LLBML.Networking;
using LLBML.Players;
using LLBML.States;
using LLBML.Utils;
using LLBT.Tweaks;
using Multiplayer;
using TinyJson;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("LLBTweaker (fr.glomzubuk.plugins.llb.llbtweaker)")]
[assembly: AssemblyProduct("LLBTweaker")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.4.0")]
[module: UnverifiableCode]
namespace LLBT
{
[BepInPlugin("fr.glomzubuk.plugins.llb.llbtweaker", "LLBTweaker", "0.1.4")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class LLBTweaker : BaseUnityPlugin
{
private int currentTweakIndex;
internal ConfigEntry<KeyCode> cycleTweaksNextKey;
internal ConfigEntry<KeyCode> cycleTweaksPreviousKey;
internal ConfigEntry<bool> enableLiveTweaking;
internal ConfigEntry<bool> restoreConfigsOnEnteringLobby;
internal ConfigEntry<KeyCode> reloadTweaksStateKey;
internal ConfigEntry<KeyCode> toggleCurrentTweakKey;
internal List<TweakBase> tweaks = new List<TweakBase>();
internal bool showVanillaWarning;
internal static ManualLogSource Log { get; private set; }
internal static ManualLogSource TweakLog { get; private set; }
internal static LLBTweaker Instance { get; private set; }
internal ConfigFile TweakConfig { get; private set; }
private void Awake()
{
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
Instance = this;
((BaseUnityPlugin)this).Logger.LogInfo((object)"Hello, world!");
InitConfigs();
TweakLog = Logger.CreateLogSource("Tweaks");
TweakConfig = new ConfigFile(Path.Combine(Paths.ConfigPath, "TweakConfigs.cfg"), true, ((BaseUnityPlugin)this).Info.Metadata);
}
private void Start()
{
TweakConfig.SaveOnConfigSet = false;
foreach (TweakBase item in tweaks.Where((TweakBase tweak) => tweak.ShouldPatch()))
{
((BaseUnityPlugin)this).Logger.LogDebug((object)("Applying tweak " + item.ID));
item.Enable();
}
Network.Init();
ModDependenciesUtils.RegisterToModMenu(((BaseUnityPlugin)this).Info, (List<string>)null);
}
private void Update()
{
if (GameStates.IsInOnlineLobby())
{
Network.OnUpdate();
}
else
{
showVanillaWarning = false;
}
if (enableLiveTweaking.Value && tweaks.Count > 0)
{
HandleLiveTweaking();
}
}
private void OnGUI()
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Expected O, but got Unknown
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
if (enableLiveTweaking.Value && tweaks.Count != 0)
{
GUIStyle val = new GUIStyle
{
fontStyle = (FontStyle)1,
fontSize = 24
};
val.normal.textColor = Color.red;
GUIStyle val2 = val;
TweakBase tweakBase = tweaks[currentTweakIndex];
GUI.Label(new Rect(20f, 20f, 400f, 25f), "Current Tweak: " + tweakBase.Name, val2);
GUI.Label(new Rect(20f, 50f, 200f, 25f), "Is Tweak Enabled: " + tweakBase.IsEnabled, val2);
}
}
private void HandleLiveTweaking()
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: 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_00de: Unknown result type (might be due to invalid IL or missing references)
if (Input.GetKeyDown(toggleCurrentTweakKey.Value))
{
if (NetworkApi.IsOnline)
{
Player localPlayer = Player.GetLocalPlayer();
if (localPlayer.nr == 0 && GameStates.IsInLobby())
{
tweaks[currentTweakIndex].Toggle();
GameStatesLobbyUtils.SendPlayerState(localPlayer);
}
}
else
{
tweaks[currentTweakIndex].Toggle();
}
}
if (Input.GetKeyDown(cycleTweaksNextKey.Value))
{
currentTweakIndex--;
if (currentTweakIndex < 0)
{
currentTweakIndex = tweaks.Count - 1;
}
}
if (Input.GetKeyDown(cycleTweaksPreviousKey.Value))
{
currentTweakIndex++;
if (currentTweakIndex >= tweaks.Count)
{
currentTweakIndex = 0;
}
}
if (Input.GetKeyDown(reloadTweaksStateKey.Value))
{
ReloadAllTweaksStates();
}
}
public static void AddTweak(TweakBase tweak)
{
Instance.tweaks.Add(tweak);
}
internal void DisableAll()
{
((BaseUnityPlugin)this).Logger.LogDebug((object)"Disabling all tweaks.");
foreach (TweakBase tweak in tweaks)
{
tweak.Disable();
}
}
internal void ReloadAllTweaksStates()
{
TweakConfig.Reload();
((BaseUnityPlugin)this).Logger.LogDebug((object)"Reloading all tweaks states.");
foreach (TweakBase tweak in tweaks)
{
tweak.Reload();
}
}
private void InitConfigs()
{
//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
//IL_00aa: Expected O, but got Unknown
toggleCurrentTweakKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Keybinds", "toggleCurrentTweak", (KeyCode)92, (ConfigDescription)null);
cycleTweaksNextKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Keybinds", "cycleTweaksNext", (KeyCode)91, (ConfigDescription)null);
cycleTweaksPreviousKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Keybinds", "cycleTweaksPrevious", (KeyCode)93, (ConfigDescription)null);
reloadTweaksStateKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Keybinds", "reloadTweaksState", (KeyCode)8, (ConfigDescription)null);
((BaseUnityPlugin)this).Config.Bind<string>("General", "headerGeneral", "General:", new ConfigDescription("", (AcceptableValueBase)null, new object[1] { "modmenu_header" }));
enableLiveTweaking = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "enableLiveTweaking", false, (ConfigDescription)null);
restoreConfigsOnEnteringLobby = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "restoreConfigsOnEnteringLobby", true, (ConfigDescription)null);
}
}
public static class PluginInfos
{
public const string PLUGIN_NAME = "LLBTweaker";
public const string PLUGIN_ID = "fr.glomzubuk.plugins.llb.llbtweaker";
public const string PLUGIN_VERSION = "0.1.4";
}
internal enum LLBT_MSGCODES : ushort
{
CHECKIN = 380,
CHECKIN_ACK,
UNKNOWN_TWEAKS,
ABORT
}
internal static class Network
{
private static readonly ManualLogSource Logger = LLBTweaker.Log;
private static bool[] playerStatuses = new bool[4];
private static bool InVanillaLobby = true;
internal static void Init()
{
//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
//IL_00ac: Expected O, but got Unknown
//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
//IL_00bd: Expected O, but got Unknown
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Expected O, but got Unknown
PluginInfo info = ((BaseUnityPlugin)LLBTweaker.Instance).Info;
PlayerLobbyState.RegisterPayload(info, (Func<PlayerLobbyState, byte[]>)OnSendLobbyState, (Action<PlayerLobbyState, byte[]>)OnReceiveLobbyState);
MessageApi.RegisterCustomMessage(info, (ushort)380, "LLBTCheckIn", (Action<Message>)ReceiveCheckIn);
MessageApi.RegisterCustomMessage(info, (ushort)381, "LLBTCheckInAck", (Action<Message>)ReceiveCheckInAck);
MessageApi.RegisterCustomMessage(info, (ushort)382, "LLBTUnknownTweaks", (Action<Message>)ReceiveUnknownTweaks);
MessageApi.RegisterCustomMessage(info, (ushort)383, "LLBTAbort", (Action<Message>)ReceiveAbort);
LobbyEvents.OnLobbyEntered += new OnLobbyEnteredHandler(OnLobbyEnteredHandler);
LobbyEvents.OnLobbyReady += new OnLobbyReadyHandler(OnLobbyReadyHandler);
LobbyEvents.OnStageSelectOpen += new OnStageSelectOpenHandler(OnStageSelectOpened);
}
internal static void OnUpdate()
{
LLBTweaker.Instance.showVanillaWarning = !AllPeersTweaked();
}
internal static bool AllPeersTweaked()
{
if (P2P.localPeer == null)
{
return true;
}
bool allTweaked = true;
((Peer)P2P.localPeer).ForAllOthers((Action<Peer>)delegate(Peer peer)
{
PlayerStatus playerStatus = Player.GetPlayer(peer.playerNr).playerStatus;
if ((EnumWrapper<AKNMBDLMNJM>)(object)playerStatus != (EnumWrapper<AKNMBDLMNJM>)(object)PlayerStatus.NONE && (EnumWrapper<AKNMBDLMNJM>)(object)playerStatus != (EnumWrapper<AKNMBDLMNJM>)(object)PlayerStatus.DISCONNECTED && !playerStatuses[peer.playerNr])
{
allTweaked = false;
}
});
return allTweaked;
}
internal static byte[] OnSendLobbyState(PlayerLobbyState pls)
{
byte[] result = null;
if (Player.GetPlayer(pls.playerNr).peer is LocalHost)
{
Dictionary<string, TweakConfigJson> dictionary = new Dictionary<string, TweakConfigJson>();
foreach (TweakBase item in LLBTweaker.Instance.tweaks.Where((TweakBase tweak) => tweak.IsEnabled))
{
dictionary.Add(item.ID, item.ConfigToJson());
}
using MemoryStream memoryStream = new MemoryStream();
using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream))
{
string text = JSONWriter.ToJson((object)dictionary);
Logger.LogDebug((object)("Sending Lobby State: " + text));
binaryWriter.Write(text);
}
result = memoryStream.ToArray();
}
return result;
}
internal static void OnReceiveLobbyState(PlayerLobbyState pls, byte[] payload)
{
List<string> list = new List<string>();
using (MemoryStream input = new MemoryStream(payload))
{
using BinaryReader binaryReader = new BinaryReader(input);
LLBTweaker.Instance.DisableAll();
string text = binaryReader.ReadString();
Logger.LogDebug((object)("Receiving LobbyState: " + text));
foreach (KeyValuePair<string, TweakConfigJson> jTweakConfig in JSONParser.FromJson<Dictionary<string, TweakConfigJson>>(text))
{
Logger.LogDebug((object)$"{jTweakConfig.Key}:\n{jTweakConfig.Value}");
TweakBase tweakBase = LLBTweaker.Instance.tweaks.Find((TweakBase _tweak) => _tweak.ID == jTweakConfig.Key);
if (tweakBase != null)
{
tweakBase.LoadJsonConfig(jTweakConfig.Value);
}
else
{
list.Add(jTweakConfig.Key);
}
}
}
if (list.Count > 0)
{
SendUnkownTweaksMessage(list);
}
}
internal static void OnLobbyEnteredHandler(object source, LobbyEventArgs args)
{
if (LLBTweaker.Instance.restoreConfigsOnEnteringLobby.Value)
{
LLBTweaker.Instance.ReloadAllTweaksStates();
}
ArrayExtension.Fill<bool>(playerStatuses, false);
InVanillaLobby = true;
}
internal static void OnLobbyReadyHandler(object source, LobbyReadyArgs args)
{
if (args.isOnline)
{
SendCheckIn();
}
}
internal static void OnStageSelectOpened(HDLIJDBFGKN source, OnStageSelectOpenArgs args)
{
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
if (NetworkApi.IsOnline)
{
if (InVanillaLobby)
{
Logger.LogDebug((object)"Entering Stage Select and current lobby is vanilla.");
LLBTweaker.Instance.DisableAll();
}
else if (Player.GetLocalPlayer().peer is LocalHost && !AllPeersTweaked())
{
P2P.SendAll(new Message((Msg)383, 0, -1, (object)null, -1));
}
}
}
internal static void SendCheckIn()
{
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
int playerNr = ((Peer)P2P.localPeer).playerNr;
Logger.LogDebug((object)$"[P{playerNr}] Sending CheckIn to P0.");
P2P.SendToPlayerNr(0, new Message((Msg)380, playerNr, 0, (object)null, -1));
}
internal static void ReceiveCheckIn(Message payload)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
int playerNr = ((Peer)P2P.localPeer).playerNr;
int playerNr2 = payload.playerNr;
Logger.LogDebug((object)$"[P{playerNr}] Received CheckIn from P{playerNr2}.");
playerStatuses[playerNr2] = true;
Logger.LogDebug((object)$"[P{playerNr}] Sending CheckInAck to P{playerNr2}.");
P2P.SendToPlayerNr(playerNr2, new Message((Msg)381, playerNr, playerNr2, (object)null, -1));
}
internal static void ReceiveCheckInAck(Message payload)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
int playerNr = ((Peer)P2P.localPeer).playerNr;
int playerNr2 = payload.playerNr;
Logger.LogDebug((object)$"[P{playerNr}] Received CheckInAck from P{playerNr2}.");
InVanillaLobby = false;
}
internal static void SendUnkownTweaksMessage(List<string> unknownTweaks)
{
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
int playerNr = ((Peer)P2P.localPeer).playerNr;
string text = JSONWriter.ToJson((object)unknownTweaks);
Logger.LogDebug((object)$"[P{playerNr}] Sending UnkownTweaks to P0 with content:\n{text}");
byte[] bytes = Encoding.ASCII.GetBytes(text);
P2P.SendToPlayerNr(0, new Message((Msg)382, ((Peer)P2P.localPeer).playerNr, 0, (object)bytes, bytes.Length));
}
internal static void ReceiveUnknownTweaks(Message payload)
{
//IL_0000: 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)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
if (payload.ob == null)
{
LLBTweaker.Log.LogWarning((object)"Received a null payload on an UnkownTweaks message. Ignoring.");
return;
}
int playerNr = ((Peer)P2P.localPeer).playerNr;
int playerNr2 = payload.playerNr;
string @string = Encoding.ASCII.GetString(payload.ob as byte[]);
Logger.LogDebug((object)$"[P{playerNr}] Received UnknownTweaks from P{playerNr2} with content:\n{@string}");
List<string> missingTweakIDs = JSONParser.FromJson<List<string>>(@string);
GameStatesLobbyUtils.MakeSureReadyIs(false, true);
TmpRemoveMissingTweaks(missingTweakIDs);
GameStatesLobbyUtils.SendPlayerState(Player.GetLocalPlayer());
}
internal static void TmpRemoveMissingTweaks(List<string> missingTweakIDs)
{
foreach (TweakBase tweak in LLBTweaker.Instance.tweaks)
{
if (missingTweakIDs.Contains(tweak.ID))
{
Logger.LogDebug((object)("Unpatching " + tweak.Name + " on request."));
tweak.Disable();
}
}
}
internal static void ReceiveAbort(Message payload)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
int playerNr = ((Peer)P2P.localPeer).playerNr;
int playerNr2 = payload.playerNr;
Logger.LogDebug((object)$"[P{playerNr}] Received Abort from P{playerNr2}.");
LLBTweaker.Instance.DisableAll();
}
}
}
namespace LLBT.Tweaks
{
public abstract class TweakBase
{
protected ConfigEntry<bool> tweakEnabled;
public Dictionary<ConfigDefinition, ConfigEntryBase> tweakConfigs;
public static ManualLogSource Logger => LLBTweaker.TweakLog;
protected static ConfigFile Config => LLBTweaker.Instance.TweakConfig;
public string ID { get; protected set; }
public string Name { get; protected set; }
public bool IsEnabled { get; protected set; }
protected TweakBase(string tweakID, string tweakName)
{
ID = tweakID;
Name = tweakName;
tweakEnabled = Config.Bind<bool>("TweakToggles", tweakID, true, (ConfigDescription)null);
tweakConfigs = new Dictionary<ConfigDefinition, ConfigEntryBase>();
Logger.LogInfo((object)(ID + " settedUp"));
}
protected abstract void DoPatch();
protected abstract void DoUnpatch();
public bool ShouldPatch()
{
if (!IsEnabled)
{
return tweakEnabled.Value;
}
return false;
}
public bool ShouldUnpatch()
{
if (IsEnabled)
{
return !tweakEnabled.Value;
}
return false;
}
public void UpdateState()
{
if (ShouldPatch())
{
DoPatch();
}
if (ShouldUnpatch())
{
DoUnpatch();
}
}
public void Enable()
{
tweakEnabled.Value = true;
UpdateState();
}
public void Disable()
{
tweakEnabled.Value = false;
UpdateState();
}
public void Toggle()
{
tweakEnabled.Value = !tweakEnabled.Value;
UpdateState();
}
public void Reload()
{
DoUnpatch();
UpdateState();
}
public void AddConfig(ConfigEntryBase config)
{
tweakConfigs.Add(config.Definition, config);
}
public TweakConfigJson ConfigToJson()
{
TweakConfigJson tweakConfigJson = default(TweakConfigJson);
tweakConfigJson.enabled = tweakEnabled.Value;
TweakConfigJson result = tweakConfigJson;
List<ConfigEntryJson> list = new List<ConfigEntryJson>();
foreach (ConfigEntryBase value in tweakConfigs.Values)
{
list.Add(new ConfigEntryJson
{
Key = value.Definition.Key,
Section = value.Definition.Section,
value = value.GetSerializedValue()
});
}
result.configs = list;
return result;
}
public void LoadJsonConfig(TweakConfigJson jTweakObject)
{
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Expected O, but got Unknown
tweakEnabled.Value = jTweakObject.enabled;
foreach (ConfigEntryJson config in jTweakObject.configs)
{
ConfigDefinition val = new ConfigDefinition(config.Section, config.Key);
Config[val].SetSerializedValue(config.value);
}
Reload();
}
}
public struct TweakConfigJson
{
public bool enabled;
public List<ConfigEntryJson> configs;
public override string ToString()
{
return $"enabled: {enabled}\n" + "Configs:\n\t" + GeneralExtensions.Join<ConfigEntryJson>((IEnumerable<ConfigEntryJson>)configs, (Func<ConfigEntryJson, string>)((ConfigEntryJson ce) => ce.ToString()), "\n\t");
}
}
public struct ConfigEntryJson
{
public string Section;
public string Key;
public string value;
public override string ToString()
{
return "[" + Section + "." + Key + "]: " + value;
}
}
public class HarmonyTweak : TweakBase
{
protected List<Type> patchClasses;
private readonly Harmony harmonyInstance;
public static HarmonyTweak Create(Type patchClass)
{
string tweakID = "HarmonyTweak_" + patchClass.Name;
string name = patchClass.Name;
HarmonyTweak harmonyTweak = new HarmonyTweak(tweakID, name);
harmonyTweak.AddPatchClass(patchClass);
return harmonyTweak;
}
public HarmonyTweak(string tweakID, string tweakName, Harmony harmonyInstance = null)
: base(tweakID, tweakName)
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
this.harmonyInstance = (Harmony)(((object)harmonyInstance) ?? ((object)new Harmony(tweakID)));
patchClasses = new List<Type>();
}
protected void AddPatchClass(Type patchClass, bool addConfig = false)
{
patchClasses.Add(patchClass);
if (addConfig)
{
ConfigEntry<bool> config = TweakBase.Config.Bind<bool>("PatchToggles." + base.ID, patchClass.Name, true, (ConfigDescription)null);
AddConfig((ConfigEntryBase)(object)config);
}
}
protected override void DoPatch()
{
if (base.IsEnabled)
{
return;
}
TweakBase.Logger.LogDebug((object)("Applying " + base.Name));
foreach (Type patchClass in patchClasses)
{
harmonyInstance.PatchAll(patchClass);
}
base.IsEnabled = true;
}
protected override void DoUnpatch()
{
if (base.IsEnabled)
{
TweakBase.Logger.LogDebug((object)("Unpatching " + base.Name));
harmonyInstance.UnpatchSelf();
base.IsEnabled = false;
}
}
}
public class FieldTweak<TClass, TField> : TweakBase where TClass : class
{
protected readonly FieldRef<TClass, TField> fieldRef;
protected readonly TField newValue;
protected TField initialValue;
protected TClass instance;
public static FieldTweak<_TClass, _TField> Create<_TClass, _TField>(FieldInfo _fieldInfo, _TField _newValue) where _TClass : class
{
string patchID = "FieldPatch_" + _fieldInfo.Name;
string name = _fieldInfo.Name;
return new FieldTweak<_TClass, _TField>(patchID, name, _fieldInfo, _newValue);
}
public static FieldTweak<_TClass, _TField> Create<_TClass, _TField>(FieldInfo _fieldInfo, _TField _newValue, _TClass _instance) where _TClass : class
{
string patchID = "FieldPatch_" + _fieldInfo.Name;
string name = _fieldInfo.Name;
return new FieldTweak<_TClass, _TField>(patchID, name, _fieldInfo, _newValue, _instance);
}
public FieldTweak(string _patchID, string _patchName, FieldInfo _fieldInfo, TField _newValue, TClass _instance = null)
: base(_patchID, _patchName)
{
fieldRef = AccessTools.FieldRefAccess<TClass, TField>(_fieldInfo);
newValue = _newValue;
instance = _instance;
}
public void SetInstance(TClass _instance)
{
instance = _instance;
}
public TField GetFieldValue()
{
return fieldRef.Invoke(instance);
}
protected override void DoPatch()
{
if (!base.IsEnabled && instance != null)
{
try
{
TField val = fieldRef.Invoke(instance);
initialValue = val;
val = newValue;
}
catch (Exception)
{
}
}
throw new NotImplementedException();
}
protected override void DoUnpatch()
{
throw new NotImplementedException();
}
}
}