using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using BoplModSyncer.Utils;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Steamworks;
using Steamworks.Data;
using TMPro;
using TinyJson;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.6", FrameworkDisplayName = ".NET Framework 4.6")]
[assembly: AssemblyCompany("BoplModSyncer")]
[assembly: AssemblyConfiguration("Thunderstore")]
[assembly: AssemblyDescription("Checks if all connected players have necessary mods")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+6b35826ca40c07445c3c7a81ed56537f4e736479")]
[assembly: AssemblyProduct("BoplModSyncer")]
[assembly: AssemblyTitle("BoplModSyncer")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class IsReadOnlyAttribute : Attribute
{
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace TinyJson
{
public static class JSONParser
{
[ThreadStatic]
private static Stack<List<string>> splitArrayPool;
[ThreadStatic]
private static StringBuilder stringBuilder;
[ThreadStatic]
private static Dictionary<Type, Dictionary<string, FieldInfo>> fieldInfoCache;
[ThreadStatic]
private static Dictionary<Type, Dictionary<string, PropertyInfo>> propertyInfoCache;
public static T FromJson<T>(this string json)
{
if (propertyInfoCache == null)
{
propertyInfoCache = new Dictionary<Type, Dictionary<string, PropertyInfo>>();
}
if (fieldInfoCache == null)
{
fieldInfoCache = new Dictionary<Type, Dictionary<string, FieldInfo>>();
}
if (stringBuilder == null)
{
stringBuilder = new StringBuilder();
}
if (splitArrayPool == null)
{
splitArrayPool = new Stack<List<string>>();
}
stringBuilder.Length = 0;
for (int i = 0; i < json.Length; i++)
{
char c = json[i];
if (c == '"')
{
i = AppendUntilStringEnd(appendEscapeCharacter: true, i, json);
}
else if (!char.IsWhiteSpace(c))
{
stringBuilder.Append(c);
}
}
return (T)ParseValue(typeof(T), stringBuilder.ToString());
}
private static int AppendUntilStringEnd(bool appendEscapeCharacter, int startIdx, string json)
{
stringBuilder.Append(json[startIdx]);
for (int i = startIdx + 1; i < json.Length; i++)
{
if (json[i] == '\\')
{
if (appendEscapeCharacter)
{
stringBuilder.Append(json[i]);
}
stringBuilder.Append(json[i + 1]);
i++;
}
else
{
if (json[i] == '"')
{
stringBuilder.Append(json[i]);
return i;
}
stringBuilder.Append(json[i]);
}
}
return json.Length - 1;
}
private static List<string> Split(string json)
{
List<string> list = ((splitArrayPool.Count > 0) ? splitArrayPool.Pop() : new List<string>());
list.Clear();
if (json.Length == 2)
{
return list;
}
int num = 0;
stringBuilder.Length = 0;
for (int i = 1; i < json.Length - 1; i++)
{
switch (json[i])
{
case '[':
case '{':
num++;
break;
case ']':
case '}':
num--;
break;
case '"':
i = AppendUntilStringEnd(appendEscapeCharacter: true, i, json);
continue;
case ',':
case ':':
if (num == 0)
{
list.Add(stringBuilder.ToString());
stringBuilder.Length = 0;
continue;
}
break;
}
stringBuilder.Append(json[i]);
}
list.Add(stringBuilder.ToString());
return list;
}
internal static object ParseValue(Type type, string json)
{
if (type == typeof(string))
{
if (json.Length <= 2)
{
return string.Empty;
}
StringBuilder stringBuilder = new StringBuilder(json.Length);
for (int i = 1; i < json.Length - 1; i++)
{
if (json[i] == '\\' && i + 1 < json.Length - 1)
{
int num = "\"\\nrtbf/".IndexOf(json[i + 1]);
if (num >= 0)
{
stringBuilder.Append("\"\\\n\r\t\b\f/"[num]);
i++;
continue;
}
if (json[i + 1] == 'u' && i + 5 < json.Length - 1 && uint.TryParse(json.Substring(i + 2, 4), NumberStyles.AllowHexSpecifier, null, out var result))
{
stringBuilder.Append((char)result);
i += 5;
continue;
}
}
stringBuilder.Append(json[i]);
}
return stringBuilder.ToString();
}
if (type.IsPrimitive)
{
return Convert.ChangeType(json, type, CultureInfo.InvariantCulture);
}
if (type == typeof(decimal))
{
decimal.TryParse(json, NumberStyles.Float, CultureInfo.InvariantCulture, out var result2);
return result2;
}
if (type == typeof(DateTime))
{
DateTime.TryParse(json.Replace("\"", ""), CultureInfo.InvariantCulture, DateTimeStyles.None, out var result3);
return result3;
}
if (json == "null")
{
return null;
}
if (type.IsEnum)
{
if (json[0] == '"')
{
json = json.Substring(1, json.Length - 2);
}
try
{
return Enum.Parse(type, json, ignoreCase: false);
}
catch
{
return 0;
}
}
if (type.IsArray)
{
Type elementType = type.GetElementType();
if (json[0] != '[' || json[json.Length - 1] != ']')
{
return null;
}
List<string> list = Split(json);
Array array = Array.CreateInstance(elementType, list.Count);
for (int j = 0; j < list.Count; j++)
{
array.SetValue(ParseValue(elementType, list[j]), j);
}
splitArrayPool.Push(list);
return array;
}
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))
{
Type type2 = type.GetGenericArguments()[0];
if (json[0] != '[' || json[json.Length - 1] != ']')
{
return null;
}
List<string> list2 = Split(json);
IList list3 = (IList)type.GetConstructor(new Type[1] { typeof(int) }).Invoke(new object[1] { list2.Count });
for (int k = 0; k < list2.Count; k++)
{
list3.Add(ParseValue(type2, list2[k]));
}
splitArrayPool.Push(list2);
return list3;
}
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<, >))
{
Type[] genericArguments = type.GetGenericArguments();
Type type3 = genericArguments[0];
Type type4 = genericArguments[1];
if (type3 != typeof(string))
{
return null;
}
if (json[0] != '{' || json[json.Length - 1] != '}')
{
return null;
}
List<string> list4 = Split(json);
if (list4.Count % 2 != 0)
{
return null;
}
IDictionary dictionary = (IDictionary)type.GetConstructor(new Type[1] { typeof(int) }).Invoke(new object[1] { list4.Count / 2 });
for (int l = 0; l < list4.Count; l += 2)
{
if (list4[l].Length > 2)
{
string key = list4[l].Substring(1, list4[l].Length - 2);
object value = ParseValue(type4, list4[l + 1]);
dictionary[key] = value;
}
}
return dictionary;
}
if (type == typeof(object))
{
return ParseAnonymousValue(json);
}
if (json[0] == '{' && json[json.Length - 1] == '}')
{
return ParseObject(type, json);
}
return null;
}
private static object ParseAnonymousValue(string json)
{
if (json.Length == 0)
{
return null;
}
if (json[0] == '{' && json[json.Length - 1] == '}')
{
List<string> list = Split(json);
if (list.Count % 2 != 0)
{
return null;
}
Dictionary<string, object> dictionary = new Dictionary<string, object>(list.Count / 2);
for (int i = 0; i < list.Count; i += 2)
{
dictionary[list[i].Substring(1, list[i].Length - 2)] = ParseAnonymousValue(list[i + 1]);
}
return dictionary;
}
if (json[0] == '[' && json[json.Length - 1] == ']')
{
List<string> list2 = Split(json);
List<object> list3 = new List<object>(list2.Count);
for (int j = 0; j < list2.Count; j++)
{
list3.Add(ParseAnonymousValue(list2[j]));
}
return list3;
}
if (json[0] == '"' && json[json.Length - 1] == '"')
{
string text = json.Substring(1, json.Length - 2);
return text.Replace("\\", string.Empty);
}
if (char.IsDigit(json[0]) || json[0] == '-')
{
if (json.Contains("."))
{
double.TryParse(json, NumberStyles.Float, CultureInfo.InvariantCulture, out var result);
return result;
}
int.TryParse(json, out var result2);
return result2;
}
if (json == "true")
{
return true;
}
if (json == "false")
{
return false;
}
return null;
}
private static Dictionary<string, T> CreateMemberNameDictionary<T>(T[] members) where T : MemberInfo
{
Dictionary<string, T> dictionary = new Dictionary<string, T>(StringComparer.OrdinalIgnoreCase);
foreach (T val in members)
{
if (val.IsDefined(typeof(IgnoreDataMemberAttribute), inherit: true))
{
continue;
}
string name = val.Name;
if (val.IsDefined(typeof(DataMemberAttribute), inherit: true))
{
DataMemberAttribute dataMemberAttribute = (DataMemberAttribute)Attribute.GetCustomAttribute(val, typeof(DataMemberAttribute), inherit: true);
if (!string.IsNullOrEmpty(dataMemberAttribute.Name))
{
name = dataMemberAttribute.Name;
}
}
dictionary.Add(name, val);
}
return dictionary;
}
private static object ParseObject(Type type, string json)
{
object uninitializedObject = FormatterServices.GetUninitializedObject(type);
List<string> list = Split(json);
if (list.Count % 2 != 0)
{
return uninitializedObject;
}
if (!fieldInfoCache.TryGetValue(type, out var value))
{
value = CreateMemberNameDictionary(type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy));
fieldInfoCache.Add(type, value);
}
if (!propertyInfoCache.TryGetValue(type, out var value2))
{
value2 = CreateMemberNameDictionary(type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy));
propertyInfoCache.Add(type, value2);
}
for (int i = 0; i < list.Count; i += 2)
{
if (list[i].Length > 2)
{
string key = list[i].Substring(1, list[i].Length - 2);
string json2 = list[i + 1];
PropertyInfo value4;
if (value.TryGetValue(key, out var value3))
{
value3.SetValue(uninitializedObject, ParseValue(value3.FieldType, json2));
}
else if (value2.TryGetValue(key, out value4))
{
value4.SetValue(uninitializedObject, ParseValue(value4.PropertyType, json2), null);
}
}
}
return uninitializedObject;
}
}
public static class JSONWriter
{
public static string ToJson(this object item)
{
StringBuilder stringBuilder = new StringBuilder();
AppendValue(stringBuilder, item);
return stringBuilder.ToString();
}
private static void AppendValue(StringBuilder stringBuilder, object item)
{
if (item == null)
{
stringBuilder.Append("null");
return;
}
Type type = item.GetType();
if (type == typeof(string) || type == typeof(char))
{
stringBuilder.Append('"');
string text = item.ToString();
for (int i = 0; i < text.Length; i++)
{
if (text[i] < ' ' || text[i] == '"' || text[i] == '\\')
{
stringBuilder.Append('\\');
int num = "\"\\\n\r\t\b\f".IndexOf(text[i]);
if (num >= 0)
{
stringBuilder.Append("\"\\nrtbf"[num]);
}
else
{
stringBuilder.AppendFormat("u{0:X4}", (uint)text[i]);
}
}
else
{
stringBuilder.Append(text[i]);
}
}
stringBuilder.Append('"');
}
else if (type == typeof(byte) || type == typeof(sbyte))
{
stringBuilder.Append(item.ToString());
}
else if (type == typeof(short) || type == typeof(ushort))
{
stringBuilder.Append(item.ToString());
}
else if (type == typeof(int) || type == typeof(uint))
{
stringBuilder.Append(item.ToString());
}
else if (type == typeof(long) || type == typeof(ulong))
{
stringBuilder.Append(item.ToString());
}
else if (type == typeof(float))
{
stringBuilder.Append(((float)item).ToString(CultureInfo.InvariantCulture));
}
else if (type == typeof(double))
{
stringBuilder.Append(((double)item).ToString(CultureInfo.InvariantCulture));
}
else if (type == typeof(decimal))
{
stringBuilder.Append(((decimal)item).ToString(CultureInfo.InvariantCulture));
}
else if (type == typeof(bool))
{
stringBuilder.Append(((bool)item) ? "true" : "false");
}
else if (type == typeof(DateTime))
{
stringBuilder.Append('"');
stringBuilder.Append(((DateTime)item).ToString(CultureInfo.InvariantCulture));
stringBuilder.Append('"');
}
else if (type.IsEnum)
{
stringBuilder.Append('"');
stringBuilder.Append(item.ToString());
stringBuilder.Append('"');
}
else if (item is IList)
{
stringBuilder.Append('[');
bool flag = true;
IList list = item as IList;
for (int j = 0; j < list.Count; j++)
{
if (flag)
{
flag = false;
}
else
{
stringBuilder.Append(',');
}
AppendValue(stringBuilder, list[j]);
}
stringBuilder.Append(']');
}
else
{
if (!type.IsGenericType || !(type.GetGenericTypeDefinition() == typeof(Dictionary<, >)))
{
return;
}
Type type2 = type.GetGenericArguments()[0];
if (type2 != typeof(string))
{
stringBuilder.Append("{}");
return;
}
stringBuilder.Append('{');
IDictionary dictionary = item as IDictionary;
bool flag2 = true;
foreach (object key in dictionary.Keys)
{
if (flag2)
{
flag2 = false;
}
else
{
stringBuilder.Append(',');
}
stringBuilder.Append('"');
stringBuilder.Append((string)key);
stringBuilder.Append("\":");
AppendValue(stringBuilder, dictionary[key]);
}
stringBuilder.Append('}');
}
}
}
}
namespace BoplModSyncer
{
internal static class Patches
{
private static readonly string checksumField = GameUtils.GenerateField("checksum");
private static readonly string hostModListField = GameUtils.GenerateField("modlist");
private static readonly string hostConfigListField = GameUtils.GenerateField("configlist");
private static readonly string memberHasSyncerField = GameUtils.GenerateField("syncer");
private static bool firstJoin = true;
private static bool hostSetupDone = false;
private static bool isHost = false;
public static void OnEnterLobby_Prefix(Lobby lobby)
{
//IL_00df: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
hostSetupDone = (isHost = false);
if (SteamManager.LocalPlayerIsLobbyOwner)
{
if (firstJoin && Plugin.lastLobbyId.Value != 0)
{
Plugin.logger.LogMessage((object)("rejoining: " + Plugin.lastLobbyId.Value));
new Traverse((object)SteamManager.instance).Method("TryJoinLobby", new object[1] { Plugin.lastLobbyId.Value }).GetValue();
}
else
{
OnHostJoin(lobby);
}
return;
}
((Lobby)(ref lobby)).SetMemberData(memberHasSyncerField, "1");
string data = ((Lobby)(ref lobby)).GetData(checksumField);
firstJoin = false;
Plugin.lastLobbyId.Value = 0uL;
if (data == Plugin.CHECKSUM)
{
SyncConfigs(lobby);
}
else if (string.IsNullOrEmpty(data))
{
HostDoesntHaveSyncer(lobby);
}
else
{
ModMismatch(lobby);
}
}
private static void LeaveLobby(string message = null)
{
SteamManager.instance.LeaveLobby();
Plugin.logger.LogWarning((object)("Left lobby because: '" + message + "'"));
}
private static void HostDoesntHaveSyncer(Lobby lobby)
{
LeaveLobby("host doesnt have syncer");
PanelMaker.InstantiatePanel(Plugin.noSyncerPanel);
}
private static void InstallMods(OnlineModData[] toInstallMods, LocalModData[] toDeleteMods)
{
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
Queue<OnlineModData> modsToDownload = new Queue<OnlineModData>();
for (int i = 0; i < toInstallMods.Length; i++)
{
OnlineModData item = toInstallMods[i];
if (item.Link != "" && item.DoInstall)
{
modsToDownload.Enqueue(item);
}
}
GameObject installingPanel = PanelMaker.InstantiatePanel(Plugin.installingPanel);
Slider progressBar = PanelMaker.GetProgressBarComp();
TextMeshProUGUI percentageText = ((Component)installingPanel.transform.Find("ProgressBar/Percentage")).GetComponent<TextMeshProUGUI>();
TextMeshProUGUI infoText = PanelMaker.GetInfoText();
TextMeshProUGUI textArea = PanelMaker.GetTextAreaText();
Button okButton = PanelMaker.GetOkButtonComp();
((Selectable)okButton).interactable = false;
((Graphic)textArea).color = Color.red;
Directory.CreateDirectory(GameUtils.DownloadedModsPath);
downloadNext();
void downloadComplete()
{
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Expected O, but got Unknown
((TMP_Text)infoText).text = "Press OK to restart game";
((TMP_Text)PanelMaker.GetTitleText()).text = "Downloading completed!";
((Selectable)okButton).interactable = true;
((UnityEvent)okButton.onClick).AddListener((UnityAction)delegate
{
GameUtils.RestartGameAfterDownload(toDeleteMods);
});
}
void downloadNext()
{
if (!modsToDownload.Any())
{
downloadComplete();
}
else
{
OnlineModData downloadingMod = modsToDownload.Dequeue();
WebClient client = new WebClient();
client.OpenReadCompleted += async delegate(object sender, OpenReadCompletedEventArgs args)
{
try
{
if (args.Cancelled)
{
throw new Exception("cancelled");
}
if (args.Error != null)
{
throw args.Error;
}
string[] linkParts = downloadingMod.Link.Split(new char[1] { '/' });
string name = string.Join("-", linkParts[5], linkParts[6], linkParts[7]) + ".zip";
string path = Path.Combine(GameUtils.DownloadedModsPath, name);
Plugin.logger.LogInfo((object)("downloading: " + name));
((TMP_Text)infoText).text = downloadingMod.Guid + " v" + downloadingMod.Version;
using FileStream file = File.Create(path);
await BaseUtils.CopyToAsync(args.Result, file, new SynchronousProgress<int>(delegate(int value)
{
progressBar.value = value;
((TMP_Text)percentageText).text = $"{value}%";
}));
downloadNext();
}
catch (Exception ex2)
{
Exception ex = ex2;
Plugin.logger.LogError((object)$"error while downloading: {ex}");
((TMP_Text)textArea).text = ex.Message;
Button continueButton = ((Component)installingPanel.transform.Find("Continue Button")).GetComponent<Button>();
((Component)continueButton).gameObject.SetActive(true);
((UnityEvent)continueButton.onClick).AddListener((UnityAction)delegate
{
((Component)continueButton).gameObject.SetActive(false);
((TMP_Text)textArea).text = "";
downloadNext();
});
}
finally
{
client.Dispose();
}
};
client.OpenReadAsync(new Uri(downloadingMod.Link));
}
}
}
private static void ModMismatch(Lobby lobby)
{
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_017c: Unknown result type (might be due to invalid IL or missing references)
//IL_0183: Expected O, but got Unknown
//IL_0375: Unknown result type (might be due to invalid IL or missing references)
//IL_037f: Expected O, but got Unknown
string hostModListText = ((Lobby)(ref lobby)).GetData(hostModListField);
string data = ((Lobby)(ref lobby)).GetData(hostConfigListField);
Plugin.lastLobbyId.Value = SteamId.op_Implicit(((Lobby)(ref lobby)).Id);
LeaveLobby("Missing mods");
MethodInfo methodInfo = null;
MethodInfo[] methods = typeof(ConfigFile).GetMethods();
foreach (MethodInfo methodInfo2 in methods)
{
if (!(methodInfo2.Name != "Bind"))
{
ParameterInfo[] parameters = methodInfo2.GetParameters();
if (parameters[0].ParameterType == typeof(ConfigDefinition))
{
methodInfo = methodInfo2;
break;
}
}
}
if (methodInfo == null)
{
throw new NullReferenceException("No bind method was found");
}
string[] array = hostModListText.Split(new char[1] { '|' }, StringSplitOptions.RemoveEmptyEntries);
OnlineModData[] toInstallMods = new OnlineModData[array.Length];
int num = 0;
Dictionary<string, HostConfigEntry[]> hostConfigs = GameUtils.GetHostConfigs(data);
string[] array2 = array;
foreach (string text in array2)
{
string[] array3 = text.Split(new char[1] { ',' });
OnlineModData onlineModData = new OnlineModData(array3[0], array3[1], array3[2], array3[3]);
if (hostConfigs.TryGetValue(onlineModData.Guid, out var value))
{
ConfigFile val = new ConfigFile(Path.Combine(Paths.ConfigPath, onlineModData.Guid + ".cfg"), true);
HostConfigEntry[] array4 = value;
for (int k = 0; k < array4.Length; k++)
{
HostConfigEntry hostConfigEntry = array4[k];
object obj = ((!(hostConfigEntry.Type == typeof(string))) ? ((!hostConfigEntry.Type.IsValueType) ? null : Activator.CreateInstance(hostConfigEntry.Type)) : "");
object obj2 = methodInfo.MakeGenericMethod(hostConfigEntry.Type).Invoke(val, new object[3] { hostConfigEntry.Definition, obj, null });
((ConfigEntryBase)((obj2 is ConfigEntryBase) ? obj2 : null)).SetSerializedValue(hostConfigEntry.Value);
}
val.Save();
}
if (!Plugin.mods.TryGetValue(onlineModData.Guid, out var value2) || !(value2.Hash == onlineModData.Hash))
{
toInstallMods[num] = onlineModData;
num++;
}
}
Array.Resize(ref toInstallMods, num);
LocalModData[] toDeleteMods = Plugin.mods.Values.Where((LocalModData e) => !hostModListText.Contains(e.Hash)).ToArray();
Plugin.logger.LogWarning((object)("missing:\n\t- " + string.Join("\n\t- ", toInstallMods.Select((OnlineModData m) => m.Guid + " v" + m.Version))));
Plugin.logger.LogWarning((object)("to delete:\n\t- " + string.Join("\n\t- ", toDeleteMods.Select((LocalModData m) => $"{m.Plugin.Metadata.GUID} {m.Plugin.Metadata.Version}"))));
GameObject val2 = PanelMaker.InstantiatePanel(Plugin.missingModsPanel, (UnityAction)delegate
{
InstallMods(toInstallMods, toDeleteMods);
});
Transform row = val2.transform.Find("NeededModList/Viewport/Content/tmprow");
LinkClicker linkClicker = val2.AddComponent<LinkClicker>();
for (int l = 0; l < toInstallMods.Length; l++)
{
makeInstallRow(l);
}
for (int n = 0; n < toDeleteMods.Length; n++)
{
makeDeleteRow(n);
}
void makeDeleteRow(int index)
{
makeRow(index, toDelete: true);
}
void makeInstallRow(int index)
{
makeRow(index, toDelete: false);
}
void makeRow(int index, bool toDelete)
{
//IL_017d: Unknown result type (might be due to invalid IL or missing references)
//IL_0184: Unknown result type (might be due to invalid IL or missing references)
IModData modData2;
if (!toDelete)
{
IModData modData = toInstallMods[index];
modData2 = modData;
}
else
{
IModData modData = toDeleteMods[index];
modData2 = modData;
}
IModData modData3 = modData2;
Transform val3 = Object.Instantiate<Transform>(row, row.parent);
((Component)val3).gameObject.SetActive(true);
TextMeshProUGUI component = ((Component)val3.Find("Background/Label")).GetComponent<TextMeshProUGUI>();
Toggle component2 = ((Component)val3).GetComponent<Toggle>();
StringBuilder stringBuilder = new StringBuilder(modData3.Guid).Append(" v").Append(modData3.Version).Append(" (")
.Append(modData3.Hash.Substring(0, 4))
.Append(")");
if (!string.IsNullOrEmpty(modData3.Link))
{
string[] array5 = modData3.Link.Split(new char[1] { '/' });
string value3 = "https://thunderstore.io/c/bopl-battle/p/" + array5[5] + "/" + array5[6] + "/";
stringBuilder.Append(" <link=").Append(value3).Append("><color=blue><b>link</b></color></link>");
}
((TMP_Text)component).text = stringBuilder.ToString();
linkClicker.textMeshes.Add(component);
if (toDelete)
{
((TMP_Text)component).fontStyle = (FontStyles)(((TMP_Text)component).fontStyle | 0x40);
((UnityEvent<bool>)(object)component2.onValueChanged).AddListener((UnityAction<bool>)delegate(bool isOn)
{
toDeleteMods[index].DoDelete = isOn;
});
component2.isOn = true;
}
else if (!string.IsNullOrEmpty(modData3.Link))
{
((UnityEvent<bool>)(object)component2.onValueChanged).AddListener((UnityAction<bool>)delegate(bool isOn)
{
toInstallMods[index].DoInstall = isOn;
});
component2.isOn = true;
}
else
{
((Selectable)component2).interactable = false;
}
}
}
private static void SyncConfigs(Lobby lobby)
{
//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
//IL_01c9: Expected O, but got Unknown
//IL_011c: Unknown result type (might be due to invalid IL or missing references)
Dictionary<string, HostConfigEntry[]> hostConfigs = GameUtils.GetHostConfigs(((Lobby)(ref lobby)).GetData(hostConfigListField));
Dictionary<string, List<KeyValuePair<ConfigEntryBase, string>>> newConfigs = new Dictionary<string, List<KeyValuePair<ConfigEntryBase, string>>>();
bool flag = true;
foreach (KeyValuePair<string, LocalModData> mod in Plugin.mods)
{
ConfigFile config = mod.Value.Plugin.Instance.Config;
List<KeyValuePair<ConfigEntryBase, string>> list = new List<KeyValuePair<ConfigEntryBase, string>>();
if (!hostConfigs.TryGetValue(mod.Key, out var value))
{
continue;
}
foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in config)
{
ConfigEntryBase value2 = item.Value;
string text = "";
HostConfigEntry[] array = value;
for (int i = 0; i < array.Length; i++)
{
HostConfigEntry hostConfigEntry = array[i];
if (hostConfigEntry.Definition.Equals(value2.Definition))
{
text = hostConfigEntry.Value;
break;
}
}
if (flag && text != value2.GetSerializedValue())
{
flag = false;
Plugin.lastLobbyId.Value = SteamId.op_Implicit(((Lobby)(ref lobby)).Id);
LeaveLobby("syncing configs");
}
if (!flag)
{
list.Add(new KeyValuePair<ConfigEntryBase, string>(value2, text));
}
}
if (!flag)
{
newConfigs.Add(mod.Key, list);
}
}
if (flag)
{
return;
}
GameObject val = PanelMaker.InstantiatePanel(Plugin.restartPanel, (UnityAction)delegate
{
Directory.CreateDirectory(GameUtils.OldConfigsPath);
foreach (KeyValuePair<string, LocalModData> mod2 in Plugin.mods)
{
ConfigFile config2 = mod2.Value.Plugin.Instance.Config;
string destFileName = Path.Combine(GameUtils.OldConfigsPath, Path.GetFileName(config2.ConfigFilePath));
try
{
File.Copy(config2.ConfigFilePath, destFileName);
}
catch (IOException)
{
}
config2.SaveOnConfigSet = false;
foreach (KeyValuePair<ConfigEntryBase, string> item2 in newConfigs[mod2.Key])
{
item2.Key.SetSerializedValue(item2.Value);
}
config2.Save();
}
GameUtils.RestartGameAfterSync();
});
}
private static void OnHostJoin(Lobby lobby)
{
isHost = true;
((Lobby)(ref lobby)).SetData(checksumField, Plugin.CHECKSUM);
Dictionary<string, List<string[]>> dictionary = new Dictionary<string, List<string[]>>();
StringBuilder stringBuilder = new StringBuilder();
foreach (KeyValuePair<string, LocalModData> mod in Plugin.mods)
{
LocalModData value = mod.Value;
ConfigFile config = value.Plugin.Instance.Config;
stringBuilder.Append(mod.Key).Append(',').Append(value.Version)
.Append(',')
.Append(value.Link)
.Append(',')
.Append(value.Hash)
.Append('|');
if (config.Count == 0)
{
continue;
}
List<string[]> list = new List<string[]>();
foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in config)
{
ConfigEntryBase value2 = item.Value;
string text = value2.SettingType.FullName;
if (Type.GetType(text) == null)
{
text = value2.SettingType.AssemblyQualifiedName;
}
list.Add(new string[3]
{
item.Key.MyToString(),
text,
value2.GetSerializedValue()
});
}
dictionary.Add(mod.Key, list);
}
if (stringBuilder.Length > 0)
{
stringBuilder.RemoveLast();
}
((Lobby)(ref lobby)).SetData(hostModListField, stringBuilder.ToString());
((Lobby)(ref lobby)).SetData(hostConfigListField, dictionary.ToJson());
hostSetupDone = true;
}
internal static void OnLobbyMemberJoinedCallback_Postfix(Lobby lobby, Friend friend)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
if (!isHost)
{
return;
}
if (!hostSetupDone)
{
int num = SteamManager.instance.connectedPlayers.FindIndex((SteamConnection e) => SteamId.op_Implicit(e.id) == SteamId.op_Implicit(friend.Id));
if (num != -1)
{
SteamManager.instance.KickPlayer(num);
Plugin.logger.LogWarning((object)("Kicked \"" + ((Friend)(ref friend)).Name + "\" because host(you) still havent finished booting!"));
}
}
else
{
((MonoBehaviour)Plugin.plugin).StartCoroutine(waitForField());
}
IEnumerator waitForField()
{
yield return (object)new WaitForSeconds(1f);
if (!(((Lobby)(ref lobby)).GetMemberData(friend, memberHasSyncerField) == "1"))
{
int playerIndex = SteamManager.instance.connectedPlayers.FindIndex((SteamConnection e) => SteamId.op_Implicit(e.id) == SteamId.op_Implicit(friend.Id));
if (playerIndex != -1)
{
SteamManager.instance.KickPlayer(playerIndex);
Plugin.logger.LogWarning((object)("Kicked \"" + ((Friend)(ref friend)).Name + "\" because he doesnt has syncer!"));
}
}
}
}
internal static void JoinLobby_Prefix()
{
if ((Object)(object)PanelMaker.currentPanel != (Object)null)
{
((UnityEvent)PanelMaker.GetCancelButtonComp().onClick).Invoke();
}
}
}
[BepInPlugin("com.almafa64.BoplModSyncer", "BoplModSyncer", "1.0.0")]
[BepInProcess("BoplBattle.exe")]
public class Plugin : BaseUnityPlugin
{
internal const string THUNDERSTORE_BOPL_MODS = "https://thunderstore.io/c/bopl-battle/api/v1/package";
internal const string GITHUB_CLIENT_ONLY_GUIDS = "https://raw.githubusercontent.com/almafa64/almafa64-bopl-mods/dev/BoplModSyncer/client_only_guids.txt";
private static readonly Dictionary<string, LocalModData> _mods = new Dictionary<string, LocalModData>();
public static readonly ReadOnlyDictionary<string, LocalModData> mods = new ReadOnlyDictionary<string, LocalModData>(_mods);
public static readonly bool IsDemo = Path.GetFileName(Paths.GameRootPath) == "Bopl Battle Demo";
internal static Harmony harmony;
internal static ManualLogSource logger;
internal static ConfigFile config;
internal static Plugin plugin;
internal static ConfigEntry<ulong> lastLobbyId;
internal static string _checksum;
internal static readonly HashSet<string> _clientOnlyGuids = new HashSet<string>();
internal static GameObject genericPanel;
internal static GameObject missingModsPanel;
internal static GameObject noSyncerPanel;
internal static GameObject installingPanel;
internal static GameObject restartPanel;
private static GameObject checksumTextObj;
public static string CHECKSUM => _checksum ?? throw new Exception("CHECKSUM hasn't been calculated");
private void Awake()
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Expected O, but got Unknown
//IL_00db: Unknown result type (might be due to invalid IL or missing references)
//IL_00e9: Expected O, but got Unknown
//IL_0116: Unknown result type (might be due to invalid IL or missing references)
//IL_0123: Expected O, but got Unknown
//IL_0157: Unknown result type (might be due to invalid IL or missing references)
//IL_0165: Expected O, but got Unknown
harmony = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
logger = ((BaseUnityPlugin)this).Logger;
config = ((BaseUnityPlugin)this).Config;
plugin = this;
WebClient webClient = new WebClient();
string[] array = webClient.DownloadString("https://raw.githubusercontent.com/almafa64/almafa64-bopl-mods/dev/BoplModSyncer/client_only_guids.txt").Split(new char[1] { '\n' });
foreach (string text in array)
{
_clientOnlyGuids.Add(text.Trim());
}
lastLobbyId = config.Bind<ulong>("BoplModSyncer", "last lobby id", 0uL, (ConfigDescription)null);
SceneManager.sceneLoaded += OnSceneLoaded;
harmony.Patch((MethodBase)AccessTools.Method(typeof(SteamManager), "OnLobbyEnteredCallback", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Patches), "OnEnterLobby_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
harmony.Patch((MethodBase)AccessTools.Method(typeof(SteamManager), "OnLobbyMemberJoinedCallback", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "OnLobbyMemberJoinedCallback_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
harmony.Patch((MethodBase)AccessTools.Method("Steamworks.ISteamMatchmaking:JoinLobby", new Type[1] { typeof(SteamId) }, (Type[])null), new HarmonyMethod(typeof(Patches), "JoinLobby_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
AssetBundle val = AssetBundle.LoadFromStream(BaseUtils.GetResourceStream("BoplModSyncer", "PanelBundle"));
genericPanel = val.LoadAsset<GameObject>("GenericPanel");
val.Unload(false);
GameUtils.Init();
Directory.CreateDirectory(GameUtils.MyCachePath);
}
private void Start()
{
WebClient webClient = new WebClient();
List<object> list = (List<object>)webClient.DownloadString("https://thunderstore.io/c/bopl-battle/api/v1/package").FromJson<object>();
Dictionary<string, Dictionary<string, string>> dictionary = new Dictionary<string, Dictionary<string, string>>();
foreach (object item in list)
{
Dictionary<string, object> dictionary2 = item as Dictionary<string, object>;
Dictionary<string, string> dictionary3 = new Dictionary<string, string>();
foreach (object item2 in (List<object>)dictionary2["versions"])
{
Dictionary<string, object> dictionary4 = (Dictionary<string, object>)item2;
dictionary3.Add((string)dictionary4["version_number"], (string)dictionary4["download_url"]);
}
dictionary.Add((string)dictionary2["full_name"], dictionary3);
}
List<string> list2 = new List<string>();
foreach (PluginInfo value2 in Chainloader.PluginInfos.Values)
{
if (!_clientOnlyGuids.Contains(value2.Metadata.GUID))
{
string text = BaseUtils.ChecksumFile(value2.Location);
logger.LogInfo((object)(value2.Metadata.GUID + " - " + text));
list2.Add(text);
Manifest manifest = GameUtils.GetManifest(value2);
string fileName = Path.GetFileName(manifest?.Directory);
string text2 = fileName?.Substring(0, fileName.LastIndexOf('-'));
string link = ((text2 == null) ? "" : GeneralExtensions.GetValueSafe<string, string>(GeneralExtensions.GetValueSafe<string, Dictionary<string, string>>(dictionary, text2), manifest.Version));
LocalModData localModData = new LocalModData(link);
localModData.Manifest = manifest;
localModData.Plugin = value2;
localModData.Hash = text;
LocalModData value = localModData;
_mods.Add(value2.Metadata.GUID, value);
}
}
MakeChecksumText(BaseUtils.CombineHashes(list2));
PanelMaker.MakeGenericPanel(ref genericPanel);
noSyncerPanel = PanelMaker.MakeNoSyncerPanel(genericPanel);
missingModsPanel = PanelMaker.MakeMissingModsPanel(genericPanel);
installingPanel = PanelMaker.MakeInstallingPanel(genericPanel);
restartPanel = PanelMaker.MakeRestartPanel(genericPanel);
Object.Destroy((Object)(object)genericPanel);
genericPanel = null;
}
private void MakeChecksumText(string checksum)
{
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
if (_checksum != null)
{
throw new Exception("Checksum text was already made!");
}
_checksum = checksum;
Transform canvas = PanelUtils.GetCanvas();
GameObject val = GameObject.Find("ExitText");
GameObject val2 = Object.Instantiate<GameObject>(val, canvas);
((Object)val2).name = "hashText";
Object.Destroy((Object)(object)val2.GetComponent<LocalizedText>());
TextMeshProUGUI component = val2.GetComponent<TextMeshProUGUI>();
((TMP_Text)component).transform.position = val.transform.position;
((TMP_Text)component).text = checksum;
checksumTextObj = Object.Instantiate<GameObject>(val2);
((Object)checksumTextObj).hideFlags = (HideFlags)1;
Object.DontDestroyOnLoad((Object)(object)checksumTextObj);
Object.Destroy((Object)(object)val2);
ShowChecksumText(10);
}
private void ShowChecksumText(int ypos)
{
//IL_002d: 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_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)checksumTextObj == (Object)null))
{
GameObject val = Object.Instantiate<GameObject>(checksumTextObj, PanelUtils.GetCanvas());
Vector3 val2 = Camera.main.WorldToScreenPoint(val.transform.position);
val2.y = ypos;
val.transform.position = Camera.main.ScreenToWorldPoint(val2);
}
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
if (((Scene)(ref scene)).name == "MainMenu")
{
OnMainMenuloaded();
}
else if (((Scene)(ref scene)).name.Contains("Select"))
{
OnSelectMenuLoaded();
}
}
private void OnMainMenuloaded()
{
ShowChecksumText(10);
}
private void OnSelectMenuLoaded()
{
ShowChecksumText(1500);
}
}
public interface IModData
{
string Guid { get; }
string Version { get; }
string Link { get; }
string Hash { get; }
}
public struct OnlineModData : IModData
{
public string Guid { get; internal set; }
public string Version { get; internal set; }
public string Link { get; internal set; }
public string Hash { get; internal set; }
public bool DoInstall { get; internal set; }
public OnlineModData(string guid, string version, string link, string hash)
{
Guid = guid;
Version = version;
Link = link;
Hash = hash;
DoInstall = false;
}
public override readonly string ToString()
{
return "version: '" + Version + "', link: '" + Link + "', guid: '" + Guid + "', hash: '" + Hash + "'";
}
}
public struct LocalModData : IModData
{
private PluginInfo _plugin;
private Manifest _manifest;
public string Guid { get; private set; }
public string Version { get; private set; }
public string Hash { get; internal set; }
public string Link { get; internal set; }
public bool DoDelete { get; internal set; }
public PluginInfo Plugin
{
readonly get
{
return _plugin;
}
internal set
{
if (_plugin != null)
{
throw new Exception("Plugin was already set!");
}
_plugin = value;
PluginInfo plugin = _plugin;
Guid = ((plugin != null) ? plugin.Metadata.GUID : null);
if (Version == null)
{
PluginInfo plugin2 = _plugin;
string text2 = (Version = ((plugin2 != null) ? plugin2.Metadata.Version.ToString() : null));
}
}
}
public Manifest Manifest
{
readonly get
{
return _manifest;
}
internal set
{
if (_manifest != null)
{
throw new Exception("Manifest was already set!");
}
_manifest = value;
if (_manifest != null)
{
Version = _manifest.Version;
}
}
}
public LocalModData(string link)
{
Guid = null;
Version = null;
Hash = null;
_plugin = null;
_manifest = null;
Link = link;
DoDelete = false;
}
public override readonly string ToString()
{
return "name: '" + Plugin.Metadata.Name + "', version: '" + Version + "', link: '" + Link + "', guid: '" + Guid + "', hash: '" + Hash + "'";
}
}
public struct HostConfigEntry
{
internal Type Type { get; private set; }
internal string Value { get; private set; }
internal ConfigDefinition Definition { get; private set; }
public HostConfigEntry(ConfigDefinition definition, Type type, string value)
{
Type = type;
Value = value;
Definition = definition;
}
}
public class Manifest
{
public string Name { get; private set; }
public string Version { get; private set; }
public string Website { get; private set; }
public string Description { get; private set; }
public ReadOnlyCollection<string> Dependencies { get; private set; }
public string Directory { get; private set; }
internal Manifest(ManifestJSON json, string dir)
{
Name = json.name;
Version = json.version_number;
Website = json.website_url;
Description = json.description;
Dependencies = new ReadOnlyCollection<string>(json.dependencies);
Directory = dir;
}
}
internal class ManifestJSON
{
public string name = null;
public string version_number = null;
public string website_url = null;
public string description = null;
public string[] dependencies = null;
}
public static class TypeExnteders
{
public static StringBuilder RemoveLast(this StringBuilder sb)
{
return sb.Remove(sb.Length - 1, 1);
}
public static string MyToString(this ConfigDefinition def)
{
return def.Section + "=" + def.Key;
}
}
internal class LinkClicker : MonoBehaviour, IPointerClickHandler, IEventSystemHandler
{
public List<TextMeshProUGUI> textMeshes = new List<TextMeshProUGUI>();
public void OnPointerClick(PointerEventData eventData)
{
//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_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
foreach (TextMeshProUGUI textMesh in textMeshes)
{
int num = TMP_TextUtilities.FindIntersectingLink((TMP_Text)(object)textMesh, Vector2.op_Implicit(eventData.position), Camera.current);
if (num == -1)
{
continue;
}
TMP_LinkInfo val = ((TMP_Text)textMesh).textInfo.linkInfo[num];
Application.OpenURL(((TMP_LinkInfo)(ref val)).GetLinkID());
break;
}
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "BoplModSyncer";
public const string PLUGIN_NAME = "BoplModSyncer";
public const string PLUGIN_VERSION = "1.0.0";
}
}
namespace BoplModSyncer.Utils
{
public class BaseUtils
{
public static string BytesToString(byte[] bytes)
{
return BitConverter.ToString(bytes).Replace("-", "");
}
public static string ChecksumFile(string path)
{
using SHA256 sHA = SHA256.Create();
using FileStream fileStream = File.OpenRead(path);
byte[] bytes = sHA.ComputeHash(fileStream);
return BytesToString(bytes) + fileStream.Length;
}
public static string CombineHashes(List<string> hashes)
{
StringBuilder stringBuilder = new StringBuilder();
foreach (string hash in hashes)
{
stringBuilder.Append(hash);
}
using SHA256 sHA = SHA256.Create();
return BytesToString(sHA.ComputeHash(Encoding.UTF8.GetBytes(stringBuilder.ToString())));
}
public static async Task CopyToAsync(Stream source, Stream destination, IProgress<int> progress, int bufferSize = 4096, CancellationToken cancellationToken = default(CancellationToken))
{
byte[] buffer = new byte[bufferSize];
long totalBytesRead = 0L;
while (true)
{
int num;
int bytesRead = (num = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken));
if (num <= 0)
{
break;
}
await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
totalBytesRead += bytesRead;
progress.Report(Convert.ToInt32(totalBytesRead * 100 / source.Length));
}
}
public static Stream GetResourceStream(string namespaceName, string path)
{
return Assembly.GetExecutingAssembly().GetManifestResourceStream(namespaceName + "." + path);
}
public static string GetRelativePath(string path, string relativeDirectory)
{
return path.Substring(path.IndexOf(relativeDirectory) + relativeDirectory.Length);
}
}
public sealed class SynchronousProgress<T> : IProgress<T>
{
private readonly Action<T> _callback;
public SynchronousProgress(Action<T> callback)
{
_callback = callback;
base..ctor();
}
void IProgress<T>.Report(T data)
{
_callback(data);
}
}
internal static class GameUtils
{
private const string DataPrefix = "almafa64>";
public static string MyCachePath { get; private set; }
public static string DownloadedModsPath { get; private set; }
public static string OldConfigsPath { get; private set; }
public static string OldPluginPath { get; private set; }
internal static void Init()
{
MyCachePath = Path.Combine(Paths.CachePath, ((BaseUnityPlugin)Plugin.plugin).Info.Metadata.GUID);
DownloadedModsPath = Path.Combine(MyCachePath, "downloaded");
OldConfigsPath = Path.Combine(MyCachePath, "configs_old");
OldPluginPath = Path.Combine(MyCachePath, "plugins_old");
}
public static void CancelSyncing(WebClient client = null)
{
Plugin.lastLobbyId.Value = 0uL;
client?.CancelAsync();
try
{
Directory.Delete(DownloadedModsPath, recursive: true);
}
catch (DirectoryNotFoundException)
{
}
}
public static void RestartGameAfterDownload(LocalModData[] toDeleteMods)
{
int num = (Plugin.IsDemo ? 2494960 : 1686940);
int id = Process.GetCurrentProcess().Id;
string gUID = ((BaseUnityPlugin)Plugin.plugin).Info.Metadata.GUID;
string text = Path.Combine(MyCachePath, "mod_installer_deleter.bat");
string fileName = Path.GetFileName(MyCachePath);
string fileName2 = Path.GetFileName(DownloadedModsPath);
string fileName3 = Path.GetFileName(OldPluginPath);
string text2 = ";";
if (toDeleteMods != null && toDeleteMods.Length != 0)
{
text2 = "\"" + string.Join("\";\"", toDeleteMods.Select((LocalModData e) => BaseUtils.GetRelativePath(e.Plugin.Location, Paths.PluginPath + "\\"))) + "\"";
}
File.WriteAllText(text, $"@echo off\r\ncd BepInEx\\cache\\{Path.GetFileName(MyCachePath)} 2>nul\r\ngoto :start\r\n\r\n:err_check\r\nif not \"%errorlevel%\" == \"0\" (\r\n\techo\\\r\n\techo \u001b[91mthere was an error code: %errorlevel%!\u001b[0m\r\n\tpause\r\n\texit 0\r\n)\r\nexit /b 0\r\n\r\nrem wait for game to finish\r\n:start\r\ntasklist /fi \"pid eq {id}\" /fo csv 2>nul | find /i \"{id}\" > nul\r\nif \"%ERRORLEVEL%\"==\"0\" goto start\r\nset \"errorlevel=0\"\r\n\r\ncall :err_check\r\n\r\nrem only copy mods if there is no copy already\r\nif not exist \"{fileName3}\" (\r\n\techo\\\r\n\techo \u001b[92mcopying old mods to new folder\u001b[0m\r\n\trobocopy ..\\..\\plugins\\ {fileName3}\\ /e /ndl /nc /ns\r\n\tcall :err_check\r\n)\r\n\r\necho\\\r\necho \u001b[92mdeleting not needed mods\u001b[0m\r\nfor %%f in ({text2}) do del ..\\..\\plugins\\%%f\r\n\r\ncall :err_check\r\n\r\necho\\\r\necho \u001b[92mcopying downloaded dlls into mod folder\u001b[0m\r\ncd ..\\..\\plugins\r\nfor /r %%f in (..\\cache\\{fileName}\\{fileName2}\\*.zip) do (\r\n\tmd \"%%~nf\"\r\n\tcd \"%%~nf\"\r\n\ttar -xvf \"%%f\"\r\n\tcd ..\r\n)\r\ncd ..\\cache\\{Path.GetFileName(MyCachePath)}\r\n\r\ncall :err_check\r\n\r\necho\\\r\necho \u001b[92mcleanup\u001b[0m\r\nrmdir /s /q \"{fileName2}\"\r\n\r\ncall :err_check\r\n\r\necho\\\r\necho \u001b[91mRestarting game!\u001b[0m\r\nstart \"\" steam://rungameid/{num}");
Process.Start(text);
Application.Quit();
}
public static void RestartGameAfterSync()
{
int num = (Plugin.IsDemo ? 2494960 : 1686940);
int id = Process.GetCurrentProcess().Id;
string text = Path.Combine(MyCachePath, "syncer.bat");
File.WriteAllText(text, $"@echo off\r\n\r\nrem wait for game to finish\r\n:start\r\ntasklist /fi \"pid eq {id}\" /fo csv 2>nul | find /i \"{id}\" > nul\r\nif \"%ERRORLEVEL%\"==\"0\" goto start\r\nset \"errorlevel=0\"\r\n\r\ntimeout 2\r\n\r\necho\\\r\necho \u001b[91mRestarting game!\u001b[0m\r\nstart \"\" steam://rungameid/{num}");
Process.Start(text);
Application.Quit();
}
public static string GenerateField(string key)
{
return "almafa64>" + key;
}
public static Manifest GetManifest(PluginInfo plugin)
{
string text = plugin.Location;
while ((text = Path.GetDirectoryName(text)).Length > Paths.PluginPath.Length)
{
string path = Path.Combine(text, "manifest.json");
try
{
string text2 = File.ReadAllText(path);
return new Manifest(JsonUtility.FromJson<ManifestJSON>(text2), text);
}
catch (FileNotFoundException)
{
}
catch (Exception ex2)
{
Plugin.logger.LogError((object)ex2);
break;
}
}
return null;
}
public static Dictionary<string, HostConfigEntry[]> GetHostConfigs(string hostConfigListText)
{
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: Expected O, but got Unknown
Dictionary<string, HostConfigEntry[]> dictionary = new Dictionary<string, HostConfigEntry[]>();
Dictionary<string, List<string[]>> dictionary2 = hostConfigListText.FromJson<Dictionary<string, List<string[]>>>();
foreach (KeyValuePair<string, List<string[]>> item in dictionary2)
{
List<string[]> value = item.Value;
HostConfigEntry[] array = new HostConfigEntry[value.Count];
for (int i = 0; i < value.Count; i++)
{
string[] array2 = value[i];
string[] array3 = array2[0].Split(new char[1] { '=' }, 2);
array[i] = new HostConfigEntry(new ConfigDefinition(array3[0], array3[1]), Type.GetType(array2[1]), array2[2]);
}
dictionary.Add(item.Key, array);
}
return dictionary;
}
}
internal class PanelMaker
{
internal static GameObject currentPanel;
private static MainMenu currentMenu;
public static GameObject GetTitle(GameObject panel = null)
{
return ((Component)GetPanel(panel).Find("Title")).gameObject;
}
public static GameObject GetInfo(GameObject panel = null)
{
return ((Component)GetPanel(panel).Find("Info")).gameObject;
}
public static GameObject GetTextArea(GameObject panel = null)
{
return ((Component)GetPanel(panel).Find("Text")).gameObject;
}
public static GameObject GetProgressBar(GameObject panel = null)
{
return ((Component)GetPanel(panel).Find("ProgressBar")).gameObject;
}
public static GameObject GetModList(GameObject panel = null)
{
return ((Component)GetPanel(panel).Find("NeededModList")).gameObject;
}
public static GameObject GetOkButton(GameObject panel = null)
{
return ((Component)GetPanel(panel).Find("OK Button")).gameObject;
}
public static GameObject GetCancelButton(GameObject panel = null)
{
return ((Component)GetPanel(panel).Find("Cancel Button")).gameObject;
}
public static Slider GetProgressBarComp(GameObject panel = null)
{
return GetProgressBar(panel).GetComponent<Slider>();
}
public static TextMeshProUGUI GetTitleText(GameObject panel = null)
{
return GetTitle(panel).GetComponent<TextMeshProUGUI>();
}
public static TextMeshProUGUI GetInfoText(GameObject panel = null)
{
return GetInfo(panel).GetComponent<TextMeshProUGUI>();
}
public static TextMeshProUGUI GetTextAreaText(GameObject panel = null)
{
return GetTextArea(panel).GetComponent<TextMeshProUGUI>();
}
public static Button GetOkButtonComp(GameObject panel = null)
{
return GetOkButton(panel).GetComponent<Button>();
}
public static Button GetCancelButtonComp(GameObject panel = null)
{
return GetCancelButton(panel).GetComponent<Button>();
}
private static Transform GetPanel(GameObject panel)
{
return (panel ?? currentPanel ?? throw new NullReferenceException("panel parameter and current panel is null")).transform;
}
private static GameObject CopyGeneric(GameObject genericPanel, string name)
{
GameObject val = Object.Instantiate<GameObject>(genericPanel);
((Object)val).hideFlags = (HideFlags)1;
Object.DontDestroyOnLoad((Object)(object)val);
((Object)val).name = name;
return val;
}
private static void SetupButtons(GameObject panel, UnityAction onOkClick)
{
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Expected O, but got Unknown
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Expected O, but got Unknown
((UnityEvent)GetOkButtonComp(panel).onClick).AddListener((UnityAction)delegate
{
close();
UnityAction obj = onOkClick;
if (obj != null)
{
obj.Invoke();
}
});
((UnityEvent)GetCancelButtonComp(panel).onClick).AddListener((UnityAction)delegate
{
GameUtils.CancelSyncing();
close();
});
void close()
{
Object.Destroy((Object)(object)panel);
currentPanel = null;
currentMenu.EnableAll();
}
}
private static TMP_FontAsset GetDefaultFont()
{
return LocalizedText.localizationTable.GetFont((Language)0, false);
}
public static void MakeGenericPanel(ref GameObject genericPanel)
{
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
//IL_0107: Unknown result type (might be due to invalid IL or missing references)
//IL_010f: 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_0176: Unknown result type (might be due to invalid IL or missing references)
TextMeshProUGUI val = GetTitle(genericPanel).AddComponent<TextMeshProUGUI>();
TextMeshProUGUI val2 = GetInfo(genericPanel).gameObject.AddComponent<TextMeshProUGUI>();
TextMeshProUGUI val3 = ((Component)genericPanel.transform.Find("OK Button/Text (TMP)")).gameObject.AddComponent<TextMeshProUGUI>();
TextMeshProUGUI val4 = ((Component)genericPanel.transform.Find("Cancel Button/Text (TMP)")).gameObject.AddComponent<TextMeshProUGUI>();
TextMeshProUGUI val5 = GetTextArea(genericPanel).gameObject.AddComponent<TextMeshProUGUI>();
((TMP_Text)val).fontSize = 56f;
((Graphic)val).color = Color.black;
((TMP_Text)val).font = GetDefaultFont();
((TMP_Text)val).alignment = (TextAlignmentOptions)513;
((TMP_Text)val).fontStyle = (FontStyles)1;
float fontSize = (((TMP_Text)val3).fontSize = 50f);
((TMP_Text)val4).fontSize = fontSize;
Color color = (((Graphic)val3).color = Color.black);
((Graphic)val4).color = color;
TMP_FontAsset font = (((TMP_Text)val3).font = GetDefaultFont());
((TMP_Text)val4).font = font;
TextAlignmentOptions alignment = (TextAlignmentOptions)514;
((TMP_Text)val3).alignment = (TextAlignmentOptions)514;
((TMP_Text)val4).alignment = alignment;
FontStyles fontStyle = (FontStyles)1;
((TMP_Text)val3).fontStyle = (FontStyles)1;
((TMP_Text)val4).fontStyle = fontStyle;
((TMP_Text)val3).text = "OK";
((TMP_Text)val4).text = "Cancel";
((TMP_Text)val2).fontSize = 50f;
((Graphic)val2).color = Color.black;
((TMP_Text)val2).font = GetDefaultFont();
((TMP_Text)val2).alignment = (TextAlignmentOptions)513;
((TMP_Text)val2).fontStyle = (FontStyles)0;
((TMP_Text)val5).fontSize = 50f;
((Graphic)val5).color = Color.black;
((TMP_Text)val5).font = GetDefaultFont();
((TMP_Text)val5).alignment = (TextAlignmentOptions)513;
((TMP_Text)val5).fontStyle = (FontStyles)0;
}
public static GameObject MakeMissingModsPanel(GameObject genericPanel)
{
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
GameObject val = CopyGeneric(genericPanel, "MissingModsPanel");
Object.Destroy((Object)(object)GetProgressBar(val));
Object.Destroy((Object)(object)GetTextArea(val));
TextMeshProUGUI val2 = ((Component)val.transform.Find("NeededModList/Viewport/Content/tmprow/Background/Label")).gameObject.AddComponent<TextMeshProUGUI>();
((TMP_Text)val2).fontSize = 50f;
((Graphic)val2).color = Color32.op_Implicit(new Color32((byte)50, (byte)50, (byte)50, byte.MaxValue));
((TMP_Text)val2).font = GetDefaultFont();
((TMP_Text)val2).alignment = (TextAlignmentOptions)513;
((Graphic)val2).raycastTarget = false;
((TMP_Text)GetTitleText(val)).text = "Missing mods";
((TMP_Text)GetInfoText(val)).text = "Install | Mod data";
return val;
}
public static GameObject MakeNoSyncerPanel(GameObject genericPanel)
{
GameObject val = CopyGeneric(genericPanel, "HostMissingSyncer");
Object.Destroy((Object)(object)GetProgressBar(val));
Object.Destroy((Object)(object)GetTextArea(val));
Object.Destroy((Object)(object)GetModList(val));
((TMP_Text)GetTitleText(val)).text = "Warning!";
((TMP_Text)GetInfoText(val)).text = "Host's missing BoplModSyncer";
return val;
}
public static GameObject MakeInstallingPanel(GameObject genericPanel)
{
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Expected O, but got Unknown
GameObject val = CopyGeneric(genericPanel, "InstallingPanel");
Object.Destroy((Object)(object)GetModList(val));
TextMeshProUGUI val2 = ((Component)val.transform.Find("ProgressBar/Percentage")).gameObject.AddComponent<TextMeshProUGUI>();
((TMP_Text)val2).fontSize = 50f;
((Graphic)val2).color = Color.black;
((TMP_Text)val2).font = GetDefaultFont();
((TMP_Text)val2).alignment = (TextAlignmentOptions)513;
((TMP_Text)GetTitleText(val)).text = "Downloading!";
GameObject val3 = Object.Instantiate<GameObject>(((Component)GetOkButtonComp(val)).gameObject, val.transform);
Button continueButton = val3.GetComponent<Button>();
((UnityEvent)continueButton.onClick).AddListener((UnityAction)delegate
{
((Component)continueButton).gameObject.SetActive(false);
});
val3.SetActive(false);
((Object)val3).name = "Continue Button";
((TMP_Text)((Component)val3.transform.Find("Text (TMP)")).GetComponent<TextMeshProUGUI>()).text = "Continue";
return val;
}
public static GameObject MakeRestartPanel(GameObject genericPanel)
{
GameObject val = CopyGeneric(genericPanel, "RestartPanel");
Object.Destroy((Object)(object)GetProgressBar(val));
Object.Destroy((Object)(object)GetTextArea(val));
Object.Destroy((Object)(object)GetModList(val));
((TMP_Text)GetTitleText(val)).text = "Warning!";
((TMP_Text)GetInfoText(val)).text = "Game will be restarted!";
return val;
}
public static GameObject InstantiatePanel(GameObject panelToInstantiate, UnityAction onOkClick = null)
{
//IL_0035: 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)
if ((Object)(object)currentPanel != (Object)null)
{
throw new Exception("'" + ((Object)currentPanel).name + "' panel is already open!");
}
Transform canvas = PanelUtils.GetCanvas();
Scene activeScene = SceneManager.GetActiveScene();
if (((Scene)(ref activeScene)).name == "MainMenu")
{
MainMenu[] componentsInChildren = ((Component)canvas).GetComponentsInChildren<MainMenu>();
foreach (MainMenu val in componentsInChildren)
{
if (val.IsEnabled)
{
val.DisableAll();
currentMenu = val;
break;
}
}
}
currentPanel = Object.Instantiate<GameObject>(panelToInstantiate, canvas);
SetupButtons(currentPanel, onOkClick);
return currentPanel;
}
}
internal class PanelUtils
{
public static Transform GetCanvas()
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Expected O, but got Unknown
Scene activeScene = SceneManager.GetActiveScene();
string name = ((Scene)(ref activeScene)).name;
if (name == "MainMenu")
{
return GameObject.Find("Canvas (1)").transform;
}
if (name.Contains("Select"))
{
return GameObject.Find("Canvas").transform;
}
GameObject val = GameObject.Find("Canvas");
if ((Object)(object)val != (Object)null)
{
return val.transform;
}
val = new GameObject("Canvas");
val.AddComponent<Canvas>();
return val.transform;
}
}
}