using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Steamworks;
using UnityEngine;
using ZstdNet;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ModConfigEnforcer")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ModConfigEnforcer")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("7e7b5c74-ddfd-4667-980a-04c189e07c67")]
[assembly: AssemblyFileVersion("4.0.4")]
[assembly: TargetFramework(".NETFramework,Version=v4.6.1", FrameworkDisplayName = ".NET Framework 4.6.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("4.0.4.0")]
[module: UnverifiableCode]
namespace ModConfigEnforcer;
public interface IConfigVariable
{
bool ValueChanged { get; set; }
string GetName();
bool LocalOnly();
object GetValue();
void SetValue(object o);
Type GetValueType();
void Serialize(ZPackage zpg);
bool Deserialize(ZPackage zpg);
void Cleanup();
}
public class AutomatedConfigWrapper<T> : IConfigVariable
{
private ConfigEntry<T> _ConfigFileEntry;
private FieldInfo _TypedValueFI;
private T _LastValidValue;
public bool ValueChanged { get; set; }
public AutomatedConfigWrapper(ConfigEntry<T> configEntry)
{
_ConfigFileEntry = configEntry;
_ConfigFileEntry.SettingChanged += SettingChanged;
_TypedValueFI = ((object)configEntry).GetType().GetField("_typedValue", BindingFlags.Instance | BindingFlags.NonPublic);
}
private void SettingChanged(object sender, EventArgs e)
{
ref T reference = ref _LastValidValue;
T val = default(T);
if (val == null)
{
val = reference;
reference = ref val;
}
if (!reference.Equals(_ConfigFileEntry.Value))
{
if (!ConfigManager.ShouldUseLocalConfig)
{
SetValue(_LastValidValue);
}
else
{
_LastValidValue = (T)GetValue();
}
}
}
public string GetName()
{
return ((ConfigEntryBase)_ConfigFileEntry).Definition.Key;
}
public bool LocalOnly()
{
return false;
}
public Type GetValueType()
{
return typeof(T);
}
public object GetValue()
{
return ConfigManager.ShouldUseLocalConfig ? _ConfigFileEntry.Value : _LastValidValue;
}
public void SetValue(object o)
{
_LastValidValue = (T)o;
if (ConfigManager.ShouldUseLocalConfig)
{
ValueChanged = !_ConfigFileEntry.Value.Equals(_LastValidValue);
_ConfigFileEntry.Value = _LastValidValue;
}
else
{
_TypedValueFI.SetValue(_ConfigFileEntry, o);
}
}
public void Serialize(ZPackage zpg)
{
object value = GetValue();
zpg.FillZPackage(GetValueType().IsEnum ? ((object)(int)value) : value);
ValueChanged = false;
}
public bool Deserialize(ZPackage zpg)
{
return false;
}
public void Cleanup()
{
}
}
public class ConfigVariable<T> : IConfigVariable
{
private ConfigEntry<T> _ConfigFileEntry;
private T _LocalValue;
private bool _LocalOnly;
public string Key => ((ConfigEntryBase)_ConfigFileEntry).Definition.Key;
public T Value
{
get
{
if (!_LocalOnly)
{
if (!ConfigManager.ShouldUseLocalConfig)
{
return _LocalValue;
}
return _ConfigFileEntry.Value;
}
return _ConfigFileEntry.Value;
}
}
public bool ValueChanged { get; set; }
public ConfigVariable(ConfigFile config, string section, string key, T defaultValue, string description, bool localOnly)
{
_ConfigFileEntry = config.Bind<T>(section, key, defaultValue, description);
_LocalValue = _ConfigFileEntry.Value;
_LocalOnly = localOnly;
}
public ConfigVariable(ConfigFile config, string section, string key, T defaultValue, ConfigDescription description, bool localOnly)
{
_ConfigFileEntry = config.Bind<T>(section, key, defaultValue, description);
_LocalValue = _ConfigFileEntry.Value;
_LocalOnly = localOnly;
}
public ConfigVariable(ConfigEntry<T> configFileEntry)
{
_ConfigFileEntry = configFileEntry;
_LocalValue = _ConfigFileEntry.Value;
_LocalOnly = false;
}
public string GetName()
{
return Key;
}
public bool LocalOnly()
{
return _LocalOnly;
}
public Type GetValueType()
{
return typeof(T);
}
public object GetValue()
{
return Value;
}
public void SetValue(object o)
{
T val = (T)o;
if (ConfigManager.ShouldUseLocalConfig)
{
ValueChanged = !_ConfigFileEntry.Value.Equals(val);
_ConfigFileEntry.Value = val;
}
else
{
_LocalValue = val;
}
}
public void Serialize(ZPackage zpg)
{
object value = GetValue();
zpg.FillZPackage(GetValueType().IsEnum ? ((object)(int)value) : value);
ValueChanged = false;
}
public bool Deserialize(ZPackage zpg)
{
return false;
}
public void Cleanup()
{
}
}
public class ClientVariable<T> : IConfigVariable
{
private T _Value;
private string _Name;
public T Value => _Value;
public bool ValueChanged
{
get
{
return false;
}
set
{
}
}
public ClientVariable(string name, T value)
{
_Name = name;
_Value = value;
}
public string GetName()
{
return _Name;
}
public object GetValue()
{
return Value;
}
public Type GetValueType()
{
return typeof(T);
}
public void SetValue(object o)
{
_Value = (T)o;
}
public bool LocalOnly()
{
return true;
}
public void Serialize(ZPackage zpg)
{
}
public bool Deserialize(ZPackage zpg)
{
return false;
}
public void Cleanup()
{
}
}
public class FileWatcherVariable : IConfigVariable
{
private ConfigManager.ModConfig _Mod;
private string _Name;
private bool _LocalOnly;
private ZPackage _FileContents;
private string WatchedFilePath;
private string RelativePath;
private FileSystemWatcher FSW;
private Action<string, ZPackage> FileContentsChanged;
public bool ValueChanged { get; set; }
private int GetLengthOfPathCommonality(string path1, string path2)
{
path1 = Path.GetFullPath(path1).ToLower();
path2 = Path.GetFullPath(path2).ToLower();
int result = -1;
int num = Mathf.Min(path1.Length, path2.Length);
for (int i = 0; i < num; i++)
{
if (path1[i] != path2[i])
{
if (path1[i] == Path.DirectorySeparatorChar || path1[i] == Path.AltDirectorySeparatorChar)
{
if (path2[i] != Path.DirectorySeparatorChar && path2[i] != Path.AltDirectorySeparatorChar)
{
break;
}
result = i + 1;
}
else if (path2[i] == Path.DirectorySeparatorChar || path2[i] == Path.AltDirectorySeparatorChar)
{
break;
}
}
else if (path1[i] == Path.DirectorySeparatorChar || path1[i] == Path.AltDirectorySeparatorChar)
{
result = i + 1;
}
}
return result;
}
public FileWatcherVariable(ConfigManager.ModConfig mod, string filepath, bool localOnly, Action<string, ZPackage> handler)
{
//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
//IL_0106: Expected O, but got Unknown
//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
//IL_00f9: Expected O, but got Unknown
_Mod = mod;
WatchedFilePath = filepath;
int lengthOfPathCommonality = GetLengthOfPathCommonality(WatchedFilePath, Assembly.GetCallingAssembly().Location);
if (lengthOfPathCommonality == -1)
{
RelativePath = WatchedFilePath;
}
else
{
RelativePath = WatchedFilePath.Substring(lengthOfPathCommonality);
}
Plugin.Log.LogInfo((object)("Watching " + WatchedFilePath + " with RelativePath " + RelativePath));
FSW = new FileSystemWatcher(Path.GetDirectoryName(WatchedFilePath));
FSW.Filter = Path.GetFileName(filepath);
FSW.NotifyFilter = NotifyFilters.Size | NotifyFilters.LastWrite;
FSW.IncludeSubdirectories = false;
_Name = "FileWatcher_" + FSW.Filter;
_LocalOnly = localOnly;
if (File.Exists(WatchedFilePath))
{
_FileContents = new ZPackage(File.ReadAllBytes(WatchedFilePath));
}
else
{
_FileContents = new ZPackage();
}
FileContentsChanged = handler;
FSW.Changed += FSW_Changed;
FSW.EnableRaisingEvents = true;
}
private void FSW_Changed(object sender, FileSystemEventArgs e)
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Expected O, but got Unknown
if (_LocalOnly || ConfigManager.ShouldUseLocalConfig)
{
_FileContents = new ZPackage(File.ReadAllBytes(WatchedFilePath));
FileContentsChanged?.Invoke(RelativePath, _FileContents);
if (!_LocalOnly && Object.op_Implicit((Object)(object)ZNet.instance) && Plugin.IsAdmin(Player.m_localPlayer))
{
ConfigManager.SendConfigToClient(_Mod.Name, changesOnly: true, 0L);
}
}
}
public string GetName()
{
return _Name;
}
public bool LocalOnly()
{
return _LocalOnly;
}
public object GetValue()
{
return _FileContents;
}
public Type GetValueType()
{
return typeof(ZPackage);
}
public void SetValue(object o)
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Expected O, but got Unknown
ValueChanged = true;
ZPackage val = (ZPackage)((o is ZPackage) ? o : null);
_FileContents = new ZPackage(val.GetArray());
FileContentsChanged?.Invoke(RelativePath, _FileContents);
}
public void Serialize(ZPackage zpg)
{
zpg.Write(_FileContents);
}
public bool Deserialize(ZPackage zpg)
{
return false;
}
public void Cleanup()
{
FSW.Dispose();
}
}
public static class ConfigManager
{
private class PackageTrackerInfo
{
private ZPackage[] Packages;
public int Received { get; private set; }
public int Total
{
get
{
ZPackage[] packages = Packages;
if (packages == null)
{
return 0;
}
return packages.Length;
}
}
public bool Add(ZPackage zpg)
{
int num = zpg.ReadInt();
int num2 = zpg.ReadInt();
Plugin.Log.LogDebug((object)("Client received package " + num + " of " + num2));
if (Packages == null)
{
Packages = (ZPackage[])(object)new ZPackage[num2];
}
if (Packages[num - 1] == null)
{
Packages[num - 1] = zpg;
return ++Received == num2;
}
return false;
}
public ZPackage GetPackage()
{
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Expected O, but got Unknown
if (Received != Total)
{
return null;
}
using MemoryStream memoryStream = new MemoryStream();
for (int i = 0; i < Packages.Length; i++)
{
byte[] array = Packages[i].ReadByteArray();
memoryStream.Write(array, 0, array.Length);
Packages[i] = null;
}
Packages = null;
memoryStream.Flush();
return new ZPackage(memoryStream.ToArray());
}
}
public class ModConfig
{
public string Name;
public ConfigFile Config;
public List<IConfigVariable> Variables = new List<IConfigVariable>();
public Action ServerConfigReceived;
public Action ConfigReloaded;
public string GetRegistrationType()
{
bool flag = false;
bool flag2 = false;
foreach (IConfigVariable variable in Variables)
{
if (variable.GetType() == typeof(ConfigVariable<>))
{
flag = true;
}
else if (variable.GetType() == typeof(AutomatedConfigWrapper<>))
{
flag2 = true;
}
}
if (flag && flag2)
{
return "manual and automated discovery";
}
if (flag)
{
return "manual";
}
return "automated discovery";
}
public void SortVariables()
{
Variables.Sort((IConfigVariable a, IConfigVariable b) => string.Compare(a.GetName(), b.GetName()));
}
public ZPackage Serialize(bool changesOnly = false)
{
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Expected O, but got Unknown
ZPackage val = null;
bool flag = false;
for (int i = 0; i < Variables.Count; i++)
{
if (!Variables[i].LocalOnly() && (!changesOnly || Variables[i].ValueChanged))
{
if (!flag)
{
val = new ZPackage();
flag = true;
val.Write(Name);
}
val.Write(i);
Variables[i].Serialize(val);
}
}
return val;
}
public void Deserialize(ZPackage zpg)
{
while (zpg.m_reader.PeekChar() > -1)
{
int num = zpg.ReadInt();
if (num < 0 || num >= Variables.Count)
{
Plugin.Log.LogError((object)("Invalid variable index " + num + " read from package, aborting deserialization for mod " + Name));
break;
}
try
{
zpg.ReadVariable(Variables[num]);
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Exception deserializing variable " + Variables[num].GetName() + " @ " + num + " for mod " + Name + ": " + ex.Message));
break;
}
}
}
public void Cleanup()
{
foreach (IConfigVariable variable in Variables)
{
variable.Cleanup();
}
}
}
private static Dictionary<ulong, PackageTrackerInfo> PackageTracking = new Dictionary<ulong, PackageTrackerInfo>();
private const string ConfigRPCName = "ClientReceiveConfigData";
private static ulong LastPackageID;
public static bool ShouldUseLocalConfig = true;
private static readonly List<string> Mods = new List<string>();
private static readonly Dictionary<string, ModConfig> ModConfigs = new Dictionary<string, ModConfig>();
private static readonly Dictionary<string, IConfigVariable> AutomatedConfigsLocked = new Dictionary<string, IConfigVariable>();
public static event Action<string> UnknownModConfigReceived;
public static bool IsConfigLocked(string name)
{
return AutomatedConfigsLocked.ContainsKey(name);
}
public static void RegisterRPC(ZRpc zrpc)
{
zrpc.Register<ZPackage>("ClientReceiveConfigData", (Action<ZRpc, ZPackage>)ClientReceiveConfigData);
}
internal static List<ModConfig> GetRegisteredModConfigs()
{
return ModConfigs.Values.ToList();
}
internal static ModConfig GetRegisteredModConfig(string name, bool ignoreCase)
{
if (!ignoreCase)
{
if (ModConfigs.TryGetValue(name, out var value))
{
return value;
}
return null;
}
return ModConfigs.Values.FirstOrDefault((ModConfig mc) => string.Compare(mc.Name, name, ignoreCase: true) == 0);
}
public static void RegisterMod(string modName, ConfigFile configFile, Action scrd = null, Action cr = null)
{
if (ModConfigs.TryGetValue(modName, out var value))
{
value.Variables.Clear();
return;
}
Mods.Add(modName);
ModConfigs[modName] = new ModConfig
{
Name = modName,
Config = configFile,
ServerConfigReceived = scrd,
ConfigReloaded = cr
};
configFile.ConfigReloaded += ConfigFile_ConfigReloaded;
}
private static void ConfigFile_ConfigReloaded(object sender, EventArgs e)
{
if (Object.op_Implicit((Object)(object)ZNet.instance) && !ZNet.instance.IsDedicated() && !ZNet.instance.IsServer())
{
return;
}
List<ModConfig> list = new List<ModConfig>();
foreach (ModConfig item in ModConfigs.Values.Where((ModConfig mc) => mc.Config == sender))
{
list.Add(item);
item.ConfigReloaded?.Invoke();
}
if (list.Count > 0)
{
SendConfigsToClients(list, changesOnly: true);
}
}
public static ConfigVariable<T> RegisterModConfigVariable<T>(string modName, string varName, T defaultValue, string configSection, string configDescription, bool localOnly)
{
if (!ModConfigs.TryGetValue(modName, out var value))
{
return null;
}
ConfigVariable<T> configVariable = new ConfigVariable<T>(value.Config, configSection, varName, defaultValue, configDescription, localOnly);
value.Variables.Add(configVariable);
return configVariable;
}
public static ConfigVariable<T> RegisterModConfigVariable<T>(string modName, string varName, T defaultValue, string configSection, ConfigDescription configDescription, bool localOnly)
{
if (!ModConfigs.TryGetValue(modName, out var value))
{
return null;
}
ConfigVariable<T> configVariable = new ConfigVariable<T>(value.Config, configSection, varName, defaultValue, configDescription, localOnly);
value.Variables.Add(configVariable);
return configVariable;
}
public static void RegisterAutomatedModConfigVariable<T>(string modName, ConfigEntry<T> entry)
{
if (entry != null && ModConfigs.TryGetValue(modName, out var value))
{
AutomatedConfigWrapper<T> automatedConfigWrapper = new AutomatedConfigWrapper<T>(entry);
AutomatedConfigsLocked.Add(automatedConfigWrapper.GetName(), automatedConfigWrapper);
value.Variables.Add(automatedConfigWrapper);
}
}
public static ClientVariable<T> RegisterClientVariable<T>(string modName, string varName, T value)
{
ClientVariable<T> clientVariable = new ClientVariable<T>(varName, value);
if (RegisterModConfigVariable(modName, clientVariable))
{
return clientVariable;
}
return null;
}
public static bool RegisterModConfigVariable(string modName, IConfigVariable cv)
{
if (!ModConfigs.TryGetValue(modName, out var value))
{
return false;
}
value.Variables.Add(cv);
return true;
}
public static FileWatcherVariable RegisterModFileWatcher(string modName, string filePath, bool localOnly, Action<string, ZPackage> handler)
{
if (!ModConfigs.TryGetValue(modName, out var value))
{
return null;
}
FileWatcherVariable fileWatcherVariable = new FileWatcherVariable(value, filePath, localOnly, handler);
value.Variables.Add(fileWatcherVariable);
return fileWatcherVariable;
}
public static void SortModVariables(string modName)
{
if (ModConfigs.TryGetValue(modName, out var value))
{
value.SortVariables();
}
}
private static void ReadVariable(this ZPackage zp, IConfigVariable cv)
{
//IL_0231: Unknown result type (might be due to invalid IL or missing references)
//IL_026c: Unknown result type (might be due to invalid IL or missing references)
//IL_0290: Unknown result type (might be due to invalid IL or missing references)
//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
//IL_02b9: Expected O, but got Unknown
Type valueType = cv.GetValueType();
if (valueType == typeof(int))
{
cv.SetValue(zp.ReadInt());
}
else if (valueType == typeof(uint))
{
cv.SetValue(zp.ReadUInt());
}
else if (valueType == typeof(bool))
{
cv.SetValue(zp.ReadBool());
}
else if (valueType == typeof(byte))
{
cv.SetValue(zp.ReadByte());
}
else if (valueType == typeof(byte[]))
{
cv.SetValue(zp.ReadByteArray());
}
else if (valueType == typeof(char))
{
cv.SetValue(zp.ReadChar());
}
else if (valueType == typeof(sbyte))
{
cv.SetValue(zp.ReadSByte());
}
else if (valueType == typeof(long))
{
cv.SetValue(zp.ReadLong());
}
else if (valueType == typeof(ulong))
{
cv.SetValue(zp.ReadULong());
}
else if (valueType == typeof(float))
{
cv.SetValue(zp.ReadSingle());
}
else if (valueType == typeof(double))
{
cv.SetValue(zp.ReadDouble());
}
else if (valueType == typeof(string))
{
cv.SetValue(zp.ReadString());
}
else if (valueType == typeof(ZPackage))
{
cv.SetValue(zp.ReadPackage());
}
else if (valueType == typeof(List<string>))
{
int num = zp.ReadInt();
List<string> list = new List<string>(num);
for (int i = 0; i < num; i++)
{
list.Add(zp.ReadString());
}
cv.SetValue(list);
}
else if (valueType == typeof(Vector3))
{
cv.SetValue((object)new Vector3(zp.ReadSingle(), zp.ReadSingle(), zp.ReadSingle()));
}
else if (valueType == typeof(Quaternion))
{
cv.SetValue((object)new Quaternion(zp.ReadSingle(), zp.ReadSingle(), zp.ReadSingle(), zp.ReadSingle()));
}
else if (valueType == typeof(ZDOID))
{
cv.SetValue(zp.ReadZDOID());
}
else if (valueType == typeof(HitData))
{
HitData val = new HitData();
val.Deserialize(ref zp);
cv.SetValue(val);
}
else if (valueType.IsEnum)
{
cv.SetValue(zp.ReadInt());
}
else if (!cv.Deserialize(zp))
{
Plugin.Log.LogError((object)("Unable to deserialize data for " + cv.ToString()));
}
}
public static void FillZPackage(this ZPackage zp, params object[] ps)
{
ZRpc.Serialize(ps, ref zp);
}
private static ZPackage SerializeMod(string modname, bool changesOnly)
{
if (!ModConfigs.TryGetValue(modname, out var value))
{
return null;
}
return value.Serialize(changesOnly);
}
public static ZPackage[] CompressPackage(ZPackage data)
{
//IL_0000: 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_005c: Expected O, but got Unknown
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00c1: Expected O, but got Unknown
byte[] array = new Compressor().Wrap(data.GetArray());
int num = array.Length / 450000 + 1;
ZPackage[] array2 = (ZPackage[])(object)new ZPackage[num];
int num2 = array.Length / num;
LastPackageID++;
byte[] array3;
ZPackage val;
for (int i = 0; i < num - 1; i++)
{
array3 = new byte[num2];
Array.Copy(array, i * num2, array3, 0, array3.Length);
val = new ZPackage();
val.Write(LastPackageID);
val.Write(i + 1);
val.Write(num);
val.Write(array3);
array2[i] = val;
}
int num3 = (num - 1) * num2;
array3 = new byte[array.Length - num3];
Array.Copy(array, num3, array3, 0, array3.Length);
val = new ZPackage();
val.Write(LastPackageID);
val.Write(num);
val.Write(num);
val.Write(array3);
array2[^1] = val;
return array2;
}
public static void SendConfigToClient(string modname, bool changesOnly, long peerID = 0L)
{
if (!ZNet.instance.IsDedicated() && !ZNet.instance.IsServer())
{
return;
}
ZPackage val = SerializeMod(modname, changesOnly);
if (val != null)
{
ZPackage[] array = CompressPackage(val);
for (int i = 0; i < array.Length; i++)
{
ZNet.instance.m_routedRpc.InvokeRoutedRPC(peerID, "ClientReceiveConfigData", new object[1] { array[i] });
}
}
}
private static void SendConfigsToClients(List<ModConfig> list, bool changesOnly)
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Expected O, but got Unknown
if (!Object.op_Implicit((Object)(object)ZNet.instance) || (!ZNet.instance.IsDedicated() && !ZNet.instance.IsServer()))
{
return;
}
ZPackage val = new ZPackage();
foreach (ModConfig item in list)
{
ZPackage val2 = item.Serialize(changesOnly);
if (val2 != null)
{
val.Write(val2);
}
}
if (val.Size() > 0)
{
ZPackage[] array = CompressPackage(val);
for (int i = 0; i < array.Length; i++)
{
ZNet.instance.m_routedRpc.InvokeRoutedRPC(ZNetView.Everybody, "ClientReceiveConfigData", new object[1] { array[i] });
}
}
}
public static void SendConfigsToClient(ZRpc rpc)
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Expected O, but got Unknown
if (!Object.op_Implicit((Object)(object)ZNet.instance) || (!ZNet.instance.IsDedicated() && !ZNet.instance.IsServer()))
{
return;
}
ZPackage val = new ZPackage();
foreach (string mod in Mods)
{
ZPackage val2 = SerializeMod(mod, changesOnly: false);
if (val2 != null)
{
val.Write(val2);
}
}
if (val.Size() > 0)
{
ZPackage[] data = CompressPackage(val);
Plugin.instance.SendDataToZRpc(rpc, "ClientReceiveConfigData", data);
}
}
private static void ClientReceiveConfigData(ZRpc rpc, ZPackage data)
{
if (ZNet.instance.IsDedicated() || ZNet.instance.IsServer())
{
Plugin.Log.LogWarning((object)"Server should not be sent config values!");
return;
}
ulong key = data.ReadULong();
if (!PackageTracking.TryGetValue(key, out var value))
{
Plugin.Log.LogDebug((object)("Client received new packageID " + key));
value = new PackageTrackerInfo();
PackageTracking[key] = value;
}
if (value.Add(data))
{
SetConfigValues(value.GetPackage());
}
}
private static void SetConfigValues(ZPackage data)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Expected O, but got Unknown
ShouldUseLocalConfig = false;
Dictionary<string, ModConfig> dictionary = new Dictionary<string, ModConfig>();
ZPackage val = new ZPackage(new Decompressor().Unwrap(data.GetArray(), int.MaxValue).ToArray());
try
{
ZPackage val2 = val.ReadPackage();
while (val2 != null)
{
string text = val2.ReadString();
if (!string.IsNullOrWhiteSpace(text))
{
if (!ModConfigs.TryGetValue(text, out var value))
{
ConfigManager.UnknownModConfigReceived?.Invoke(text);
if (!ModConfigs.TryGetValue(text, out value))
{
Plugin.Log.LogError((object)("Could not find registered mod " + text));
continue;
}
Plugin.Log.LogInfo((object)("Client received data for previously unregistered mod config " + text));
}
value.Deserialize(val2);
dictionary[text] = value;
Plugin.Log.LogDebug((object)("Client updated with settings for mod " + text));
}
val2 = ((val.m_reader.PeekChar() == -1) ? null : val.ReadPackage());
}
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Exception on client SetConfigValues: " + ex.Message));
}
foreach (ModConfig value2 in dictionary.Values)
{
value2.ServerConfigReceived?.Invoke();
}
}
public static void ClearModConfigs()
{
Mods.Clear();
foreach (ModConfig value in ModConfigs.Values)
{
value.Cleanup();
}
ModConfigs.Clear();
AutomatedConfigsLocked.Clear();
}
}
internal sealed class Patches
{
[HarmonyPatch(typeof(ZNet))]
public static class ZNetPatches
{
[HarmonyPrefix]
[HarmonyPatch("Awake")]
public static void AwakePrefix(ZNet __instance)
{
ConfigManager.ShouldUseLocalConfig = true;
}
[HarmonyPrefix]
[HarmonyPriority(int.MaxValue)]
[HarmonyPatch("OnNewConnection")]
public static void OnNewConnectionPrefix(ZNet __instance, ZNetPeer peer)
{
ConfigManager.ShouldUseLocalConfig = true;
if (!__instance.IsDedicated() && !__instance.IsServer())
{
ConfigManager.RegisterRPC(peer.m_rpc);
}
}
[HarmonyPrefix]
[HarmonyPriority(int.MaxValue)]
[HarmonyPatch("RPC_ServerHandshake")]
public static void RPC_ServerHandshakePrefix(ZNet __instance, ZRpc rpc)
{
if (__instance.IsDedicated() || __instance.IsServer())
{
ConfigManager.SendConfigsToClient(rpc);
}
}
}
[HarmonyPatch(typeof(ConfigEntryBase))]
public static class BepinexConfigEntryBasePatch
{
[HarmonyPrefix]
[HarmonyPatch("OnSettingChanged")]
public static bool OnSettingChangedPrefix(object __instance)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
if (!ConfigManager.IsConfigLocked(((ConfigEntryBase)__instance).Definition.Key))
{
return true;
}
return ConfigManager.ShouldUseLocalConfig;
}
}
[HarmonyPatch(typeof(Terminal))]
public static class TerminalPatches
{
[Serializable]
[CompilerGenerated]
private sealed class <>c
{
public static readonly <>c <>9 = new <>c();
public static ConsoleEvent <>9__0_0;
internal void <InitTerminalPostfix>b__0_0(ConsoleEventArgs args)
{
bool flag = !Object.op_Implicit((Object)(object)ZNet.instance) || ZNet.instance.IsDedicated() || ZNet.instance.IsServer();
if (!flag)
{
flag = Object.op_Implicit((Object)(object)Player.m_localPlayer) && ZNet.instance.ListContainsId(ZNet.instance.m_adminList, ZNet.instance.GetPeer(((ZDOID)(ref ((Character)Player.m_localPlayer).m_nview.GetZDO().m_uid)).UserID).m_rpc.GetSocket().GetHostName());
}
for (int i = 0; i < args.Args.Length; i++)
{
args.Args[i] = args[i].ToLower();
}
if (args.Length == 2)
{
if (args[1] == "list")
{
foreach (ConfigManager.ModConfig registeredModConfig2 in ConfigManager.GetRegisteredModConfigs())
{
args.Context.AddString(".. " + registeredModConfig2.Name + " (" + registeredModConfig2.GetRegistrationType() + ")");
}
return;
}
if (args[1] == "reload")
{
if (flag)
{
args.Context.AddString(".. missing mod registration name");
}
else
{
args.Context.AddString("<color=orange>mce reload</color> is not available on clients in multiplayer.");
}
}
else
{
args.Context.AddString(".. unknown command option '" + args[1] + "'");
}
}
else if (args.Length > 2)
{
if (args[1] == "reload" && !flag)
{
args.Context.AddString("<color=orange>mce reload</color> is not available on clients in multiplayer.");
}
else if (args[1] == "list" || args[1] == "reload")
{
string text = "";
for (int j = 2; j < args.Length; j++)
{
text += ((j > 2) ? (" " + args[j]) : args[j]);
}
ConfigManager.ModConfig registeredModConfig = ConfigManager.GetRegisteredModConfig(text, ignoreCase: true);
if (registeredModConfig == null)
{
args.Context.AddString(".. mod named '" + text + "' not found!");
return;
}
if (args[1] == "list")
{
foreach (IConfigVariable variable in registeredModConfig.Variables)
{
string name = variable.GetType().Name;
name = name.Remove(name.IndexOf('`'));
args.Context.AddString(".. " + variable.GetName() + " :" + (variable.LocalOnly() ? " localOnly " : " ") + name + " : " + variable.GetValue());
}
return;
}
args.Context.AddString(".. reloading config for " + text);
registeredModConfig.Config.Reload();
}
else
{
args.Context.AddString(".. unknown command option '" + args[1] + "'");
}
}
else
{
args.Context.AddString("<color=orange>mce</color> command supports the following options :");
args.Context.AddString("<color=yellow>list</color> - displays a list of each mod registered with MCE and their registration method");
args.Context.AddString("<color=yellow>list <mod registration name></color> - displays a list of all config options registered for the mod");
if (flag)
{
args.Context.AddString("<color=yellow>reload <mod registration name></color> - reloads the config options from file for the mod (on servers, this will also send config updates to all clients)");
}
}
}
}
[HarmonyPostfix]
[HarmonyPatch("InitTerminal")]
public static void InitTerminalPostfix(Terminal __instance)
{
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Expected O, but got Unknown
object obj = <>c.<>9__0_0;
if (obj == null)
{
ConsoleEvent val = delegate(ConsoleEventArgs args)
{
bool flag = !Object.op_Implicit((Object)(object)ZNet.instance) || ZNet.instance.IsDedicated() || ZNet.instance.IsServer();
if (!flag)
{
flag = Object.op_Implicit((Object)(object)Player.m_localPlayer) && ZNet.instance.ListContainsId(ZNet.instance.m_adminList, ZNet.instance.GetPeer(((ZDOID)(ref ((Character)Player.m_localPlayer).m_nview.GetZDO().m_uid)).UserID).m_rpc.GetSocket().GetHostName());
}
for (int i = 0; i < args.Args.Length; i++)
{
args.Args[i] = args[i].ToLower();
}
if (args.Length == 2)
{
if (args[1] == "list")
{
foreach (ConfigManager.ModConfig registeredModConfig2 in ConfigManager.GetRegisteredModConfigs())
{
args.Context.AddString(".. " + registeredModConfig2.Name + " (" + registeredModConfig2.GetRegistrationType() + ")");
}
return;
}
if (args[1] == "reload")
{
if (flag)
{
args.Context.AddString(".. missing mod registration name");
}
else
{
args.Context.AddString("<color=orange>mce reload</color> is not available on clients in multiplayer.");
}
}
else
{
args.Context.AddString(".. unknown command option '" + args[1] + "'");
}
}
else if (args.Length > 2)
{
if (args[1] == "reload" && !flag)
{
args.Context.AddString("<color=orange>mce reload</color> is not available on clients in multiplayer.");
}
else if (args[1] == "list" || args[1] == "reload")
{
string text = "";
for (int j = 2; j < args.Length; j++)
{
text += ((j > 2) ? (" " + args[j]) : args[j]);
}
ConfigManager.ModConfig registeredModConfig = ConfigManager.GetRegisteredModConfig(text, ignoreCase: true);
if (registeredModConfig == null)
{
args.Context.AddString(".. mod named '" + text + "' not found!");
}
else
{
if (args[1] == "list")
{
foreach (IConfigVariable variable in registeredModConfig.Variables)
{
string name = variable.GetType().Name;
name = name.Remove(name.IndexOf('`'));
args.Context.AddString(".. " + variable.GetName() + " :" + (variable.LocalOnly() ? " localOnly " : " ") + name + " : " + variable.GetValue());
}
return;
}
args.Context.AddString(".. reloading config for " + text);
registeredModConfig.Config.Reload();
}
}
else
{
args.Context.AddString(".. unknown command option '" + args[1] + "'");
}
}
else
{
args.Context.AddString("<color=orange>mce</color> command supports the following options :");
args.Context.AddString("<color=yellow>list</color> - displays a list of each mod registered with MCE and their registration method");
args.Context.AddString("<color=yellow>list <mod registration name></color> - displays a list of all config options registered for the mod");
if (flag)
{
args.Context.AddString("<color=yellow>reload <mod registration name></color> - reloads the config options from file for the mod (on servers, this will also send config updates to all clients)");
}
}
};
<>c.<>9__0_0 = val;
obj = (object)val;
}
new ConsoleCommand("mce", "shows info for Mod Config Enforcer", (ConsoleEvent)obj, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
}
}
public static class ZSteamSocketPatches
{
public static bool RegisterGlobalCallbacksPrefix()
{
if (ZSteamSocket.m_statusChanged == null)
{
GCHandle gCHandle = GCHandle.Alloc(30000f, GCHandleType.Pinned);
GCHandle gCHandle2 = GCHandle.Alloc(1, GCHandleType.Pinned);
GCHandle gCHandle3 = GCHandle.Alloc(0, GCHandleType.Pinned);
try
{
ZSteamSocket.m_statusChanged = Callback<SteamNetConnectionStatusChangedCallback_t>.Create((DispatchDelegate<SteamNetConnectionStatusChangedCallback_t>)ZSteamSocket.OnStatusChanged);
SteamNetworkingUtils.SetConfigValue((ESteamNetworkingConfigValue)25, (ESteamNetworkingConfigScope)1, IntPtr.Zero, (ESteamNetworkingConfigDataType)3, gCHandle.AddrOfPinnedObject());
SteamNetworkingUtils.SetConfigValue((ESteamNetworkingConfigValue)23, (ESteamNetworkingConfigScope)1, IntPtr.Zero, (ESteamNetworkingConfigDataType)1, gCHandle2.AddrOfPinnedObject());
SteamNetworkingUtils.SetConfigValue((ESteamNetworkingConfigValue)12, (ESteamNetworkingConfigScope)1, IntPtr.Zero, (ESteamNetworkingConfigDataType)1, gCHandle3.AddrOfPinnedObject());
}
catch
{
}
try
{
ZSteamSocket.m_statusChanged = Callback<SteamNetConnectionStatusChangedCallback_t>.CreateGameServer((DispatchDelegate<SteamNetConnectionStatusChangedCallback_t>)ZSteamSocket.OnStatusChanged);
SteamGameServerNetworkingUtils.SetConfigValue((ESteamNetworkingConfigValue)25, (ESteamNetworkingConfigScope)1, IntPtr.Zero, (ESteamNetworkingConfigDataType)3, gCHandle.AddrOfPinnedObject());
SteamGameServerNetworkingUtils.SetConfigValue((ESteamNetworkingConfigValue)23, (ESteamNetworkingConfigScope)1, IntPtr.Zero, (ESteamNetworkingConfigDataType)1, gCHandle2.AddrOfPinnedObject());
SteamGameServerNetworkingUtils.SetConfigValue((ESteamNetworkingConfigValue)12, (ESteamNetworkingConfigScope)1, IntPtr.Zero, (ESteamNetworkingConfigDataType)1, gCHandle3.AddrOfPinnedObject());
}
catch
{
}
gCHandle.Free();
gCHandle2.Free();
gCHandle3.Free();
}
return false;
}
}
}
[BepInPlugin("pfhoenix.modconfigenforcer", "Mod Config Enforcer", "4.0.4")]
public class Plugin : BaseUnityPlugin
{
[CompilerGenerated]
private sealed class <SendDataViaZRpc>d__7 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public ZRpc peer;
public string rpc;
public ZPackage[] zpgs;
private int <i>5__2;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <SendDataViaZRpc>d__7(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Expected O, but got Unknown
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<i>5__2 = 0;
break;
case 1:
<>1__state = -1;
<i>5__2++;
break;
}
if (<i>5__2 < zpgs.Length)
{
peer.GetSocket().Flush();
peer.Invoke(rpc, new object[1] { zpgs[<i>5__2] });
<>2__current = (object)new WaitForSecondsRealtime(1f);
<>1__state = 1;
return true;
}
return false;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
public const string Version = "4.0.4";
private Harmony _Harmony;
public static ManualLogSource Log;
public static Plugin instance;
public static ConfigVariable<bool> OptimizeNetworking;
private void Awake()
{
instance = this;
Log = ((BaseUnityPlugin)this).Logger;
Assembly assembly = ((object)this).GetType().Assembly;
string[] array = new string[2] { "libzstd", "ZstdNet" };
foreach (string text in array)
{
Stream manifestResourceStream = assembly.GetManifestResourceStream(assembly.GetName().Name + "." + text + ".dll");
if (manifestResourceStream == null)
{
Log.LogError((object)("Failed to load " + text + ".dll from resource stream!"));
continue;
}
string pluginPath = Paths.PluginPath;
char directorySeparatorChar = Path.DirectorySeparatorChar;
string path = pluginPath + directorySeparatorChar + text + ".dll";
if (!File.Exists(path))
{
using FileStream destination = new FileStream(path, FileMode.OpenOrCreate);
manifestResourceStream.CopyTo(destination);
}
}
ConfigManager.RegisterMod("_MCE_", ((BaseUnityPlugin)this).Config);
OptimizeNetworking = ConfigManager.RegisterModConfigVariable("_MCE_", "Optimize Networking", defaultValue: true, "Networking", "Optimize Valheim's networking subsystem", localOnly: true);
_Harmony = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null);
if (!OptimizeNetworking.Value)
{
return;
}
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly2 in assemblies)
{
if (assembly2.FullName.StartsWith("assembly_valheim"))
{
Type type = assembly2.GetType("ZSteamSocket");
if (type != null)
{
MethodInfo method = type.GetMethod("RegisterGlobalCallbacks", BindingFlags.Static | BindingFlags.NonPublic);
MethodInfo method2 = typeof(Patches.ZSteamSocketPatches).GetMethod("RegisterGlobalCallbacksPrefix", BindingFlags.Static | BindingFlags.Public);
_Harmony.CreateProcessor((MethodBase)method).AddPrefix(method2).Patch();
}
break;
}
}
}
private void Start()
{
MethodInfo method = typeof(ConfigManager).GetMethod("RegisterAutomatedModConfigVariable", BindingFlags.Static | BindingFlags.Public);
foreach (PluginInfo value in Chainloader.PluginInfos.Values)
{
if ((Object)(object)value.Instance == (Object)(object)this || !Object.op_Implicit((Object)(object)value.Instance) || !((Behaviour)value.Instance).isActiveAndEnabled)
{
continue;
}
Type type = ((object)value.Instance).GetType();
FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
object obj = null;
FieldInfo[] array = fields;
foreach (FieldInfo fieldInfo in array)
{
if (string.Compare(fieldInfo.Name, "AutomatedConfigDiscovery", ignoreCase: true) == 0)
{
obj = fieldInfo.GetValue(value.Instance);
break;
}
}
if (obj == null)
{
continue;
}
Log.LogDebug((object)("... searching for configuration for " + value.Metadata.Name + " version " + value.Metadata.Version?.ToString() + " ..."));
type = obj.GetType();
Action scrd = null;
MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
MethodInfo[] array2 = methods;
foreach (MethodInfo methodInfo in array2)
{
if (string.Compare(methodInfo.Name, "ServerConfigReceived", ignoreCase: true) == 0)
{
scrd = (Action)Delegate.CreateDelegate(typeof(Action), obj, methodInfo);
break;
}
if (string.Compare(methodInfo.Name, "ConfigReloaded", ignoreCase: true) == 0)
{
_ = (Action)Delegate.CreateDelegate(typeof(Action), obj, methodInfo);
break;
}
}
string text = null;
FieldInfo[] fields2 = type.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
int num = 0;
array = fields2;
foreach (FieldInfo fieldInfo2 in array)
{
if (fieldInfo2.FieldType.IsSubclassOf(typeof(ConfigEntryBase)) && !fieldInfo2.IsNotSerialized)
{
if (text == null)
{
text = value.Metadata.Name;
ConfigManager.RegisterMod(text, value.Instance.Config, scrd);
}
method.MakeGenericMethod(fieldInfo2.FieldType.GetGenericArguments()[0]).Invoke(null, new object[2]
{
text,
fieldInfo2.GetValue(obj)
});
Log.LogDebug((object)("... bound " + fieldInfo2.Name));
num++;
}
else
{
if (!(fieldInfo2.FieldType == typeof(string)) || !fieldInfo2.Name.StartsWith("File_"))
{
continue;
}
fieldInfo2.Name.Substring(5);
MethodInfo methodInfo2 = methods.FirstOrDefault((MethodInfo m) => string.Compare(m.Name, "FileChanged", ignoreCase: true) == 0);
if (methodInfo2 != null)
{
if (text == null)
{
text = value.Metadata.Name;
ConfigManager.RegisterMod(text, value.Instance.Config, scrd);
}
ConfigManager.RegisterModFileWatcher(text, (string)fieldInfo2.GetValue(obj), fieldInfo2.IsNotSerialized, (Action<string, ZPackage>)Delegate.CreateDelegate(typeof(Action<string, ZPackage>), obj, methodInfo2));
Log.LogDebug((object)("... bound " + fieldInfo2.Name));
num++;
}
}
}
if (num == 0)
{
Log.LogWarning((object)"... no configuration found to enforce!");
}
else
{
ConfigManager.SortModVariables(text);
}
}
}
[IteratorStateMachine(typeof(<SendDataViaZRpc>d__7))]
private IEnumerator SendDataViaZRpc(ZRpc peer, string rpc, ZPackage[] zpgs)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <SendDataViaZRpc>d__7(0)
{
peer = peer,
rpc = rpc,
zpgs = zpgs
};
}
public void SendDataToZRpc(ZRpc peer, string rpc, ZPackage[] data)
{
((MonoBehaviour)this).StartCoroutine(SendDataViaZRpc(peer, rpc, data));
}
public static bool IsAdmin(Player player)
{
if (!Object.op_Implicit((Object)(object)ZNet.instance))
{
return true;
}
if (!Object.op_Implicit((Object)(object)player))
{
return false;
}
if (ZNet.instance.m_adminList == null)
{
return false;
}
return ZNet.instance.ListContainsId(ZNet.instance.m_adminList, ZNet.instance.GetPeer(((ZDOID)(ref ((Character)player).m_nview.GetZDO().m_uid)).UserID).m_rpc.GetSocket().GetHostName());
}
private void OnDestroy()
{
ConfigManager.ClearModConfigs();
if (_Harmony != null)
{
_Harmony.UnpatchSelf();
}
}
}