using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using LethalEditor.Configuration;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.SceneManagement;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("LethalEditor")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+a50a4b9309fff851727ceb7264988c601eba2a71")]
[assembly: AssemblyProduct("LethalEditor")]
[assembly: AssemblyTitle("LethalEditor")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/Kyxino/LethalEditor")]
[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]
[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 LethalEditor
{
internal class Utils
{
public static string MakeFileNameSafe(string FileName)
{
return Regex.Replace(FileName, "[\\/:*?\"<>|]", "");
}
public static void AddAllTypes()
{
TomlTypeConverter.AddConverter(typeof(AnimationCurve), (TypeConverter)(object)new AnimationCurve_TypeConverter());
TomlTypeConverter.AddConverter(typeof(string[]), (TypeConverter)(object)new StringArray_TypeConverter());
TomlTypeConverter.AddConverter(typeof(Battery), (TypeConverter)(object)new Battery_TypeConverter());
TomlTypeConverter.AddConverter(typeof(IntWithRarity[]), (TypeConverter)(object)new IntWithRarityArray_TypeConverter());
TomlTypeConverter.AddConverter(typeof(CompatibleNoun[]), (TypeConverter)(object)new CompatibleNounArray_TypeConverter());
TomlTypeConverter.AddConverter(typeof(TerminalKeyword), (TypeConverter)(object)new TerminalKeyword_TypeConverter());
TomlTypeConverter.AddConverter(typeof(TerminalNode), (TypeConverter)(object)new TerminalNode_TypeConverter());
TomlTypeConverter.AddConverter(typeof(SpawnableEnemyWithRarity[]), (TypeConverter)(object)new SpawnableEnemyWithRarityArray_TypeConverter());
TomlTypeConverter.AddConverter(typeof(SpawnableItemWithRarity[]), (TypeConverter)(object)new SpawnableItemWithRarityArray_TypeConverter());
TomlTypeConverter.AddConverter(typeof(List<SpawnableEnemyWithRarity>), (TypeConverter)(object)new SpawnableEnemyWithRarityList_TypeConverter());
TomlTypeConverter.AddConverter(typeof(List<SpawnableItemWithRarity>), (TypeConverter)(object)new SpawnableItemWithRarityList_TypeConverter());
TomlTypeConverter.AddConverter(typeof(EnemyType), (TypeConverter)(object)new EnemyType_TypeConverter());
TomlTypeConverter.AddConverter(typeof(List<ItemGroup>), (TypeConverter)(object)new ItemGroupList_TypeConverter());
TomlTypeConverter.AddConverter(typeof(RandomWeatherWithVariables[]), (TypeConverter)(object)new RandomWeatherWithVariablesArray_TypeConverter());
}
}
internal class AnimationCurve_TypeConverter : TypeConverter
{
public AnimationCurve_TypeConverter()
{
((TypeConverter)this).ConvertToObject = delegate(string input, Type type)
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected O, but got Unknown
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Expected O, but got Unknown
//IL_0321: Unknown result type (might be due to invalid IL or missing references)
//IL_0328: Expected O, but got Unknown
//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0302: Unknown result type (might be due to invalid IL or missing references)
//IL_0304: Unknown result type (might be due to invalid IL or missing references)
if (type != typeof(AnimationCurve))
{
return (object)new AnimationCurve();
}
string text = Regex.Replace(input, "[\\s%()%[\\]]+", "");
string[] array2 = text.Split(',');
if (string.IsNullOrEmpty(array2[0]))
{
return (object)new AnimationCurve();
}
Keyframe[] array3 = (Keyframe[])(object)new Keyframe[array2.Length];
Keyframe val2 = default(Keyframe);
for (int j = 0; j < array3.Length; j++)
{
string[] array4 = array2[j].Split(';');
string[] array5 = ((array4 != null && array4.Length >= 1) ? ((array4 != null) ? array4[0]?.Split(':') : null) : null);
string[] array6 = ((array4 != null && array4.Length >= 2) ? ((array4 != null) ? array4[1]?.Split('|') : null) : null);
string[] array7 = ((array4 != null && array4.Length >= 3) ? ((array4 != null) ? array4[2]?.Split(':') : null) : null);
string[] array8 = ((array7 != null && array7.Length >= 2) ? ((array7 != null) ? array7[1] : null) : ((array7 != null) ? array7[0] : null))?.Split('|');
float result = (float.TryParse(((array5 != null) ? array5[0] : null) ?? "0", NumberStyles.Float, new CultureInfo("en-US"), out result) ? result : 0f);
float result2 = (float.TryParse((array5 != null && array5.Length >= 2) ? ((array5 != null) ? array5[1] : null) : "0", NumberStyles.Float, new CultureInfo("en-US"), out result2) ? result2 : 0f);
float result3 = (float.TryParse(((array6 != null) ? array6[0] : null) ?? "0", NumberStyles.Float, new CultureInfo("en-US"), out result3) ? result3 : 0f);
float result4 = (float.TryParse((array6 != null && array6.Length >= 2) ? ((array6 != null) ? array6[1] : null) : (((array6 != null) ? array6[0] : null) ?? "0"), NumberStyles.Float, new CultureInfo("en-US"), out result4) ? result4 : 0f);
float result5 = (float.TryParse(((array8 != null) ? array8[0] : null) ?? "0", NumberStyles.Float, new CultureInfo("en-US"), out result5) ? result5 : 0f);
float result6 = (float.TryParse((array8 != null && array8.Length >= 2) ? ((array8 != null) ? array8[1] : null) : (((array8 != null) ? array8[0] : null) ?? "0"), NumberStyles.Float, new CultureInfo("en-US"), out result6) ? result6 : 0f);
int result7 = (int.TryParse(((array7 != null) ? array7[0] : null) ?? "0", NumberStyles.Float, new CultureInfo("en-US"), out result7) ? result7 : 0);
((Keyframe)(ref val2))..ctor(result, result2, result3, result4, result5, result6);
((Keyframe)(ref val2)).weightedMode = (WeightedMode)result7;
Keyframe val3 = val2;
array3[j] = val3;
}
return (object)new AnimationCurve(array3);
};
((TypeConverter)this).ConvertToString = delegate(object input, Type type)
{
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: Expected I4, but got Unknown
if (type != typeof(AnimationCurve))
{
return "";
}
Keyframe[] keys = ((AnimationCurve)input).keys;
if (keys.Length == 0)
{
return "";
}
if (keys.Length == 1)
{
return ((Keyframe)(ref keys[0])).value.ToString(new CultureInfo("en-US"));
}
StringBuilder stringBuilder = new StringBuilder();
Keyframe[] array = keys;
for (int i = 0; i < array.Length; i++)
{
Keyframe val = array[i];
float time = ((Keyframe)(ref val)).time;
float value = ((Keyframe)(ref val)).value;
float inTangent = ((Keyframe)(ref val)).inTangent;
float outTangent = ((Keyframe)(ref val)).outTangent;
float inWeight = ((Keyframe)(ref val)).inWeight;
float outWeight = ((Keyframe)(ref val)).outWeight;
int num = (int)((Keyframe)(ref val)).weightedMode;
stringBuilder.Append(time.ToString(new CultureInfo("en-US")) + ":" + value.ToString(new CultureInfo("en-US")));
if (inTangent != 0f || outTangent != 0f)
{
stringBuilder.Append((inTangent == outTangent) ? $";({inTangent})" : $";({inTangent}|{outTangent})");
if (inWeight != 0f || outWeight != 0f)
{
stringBuilder.Append((num != 0) ? (";" + num.ToString(new CultureInfo("en-US")) + ":") : ";");
stringBuilder.Append((inWeight == outWeight) ? ("[" + inWeight.ToString(new CultureInfo("en-US")) + "]") : ("[" + inWeight.ToString(new CultureInfo("en-US")) + "|" + outWeight.ToString(new CultureInfo("en-US")) + "]"));
}
else if (num != 0)
{
stringBuilder.Append(";" + num.ToString(new CultureInfo("en-US")));
}
}
stringBuilder.Append(", ");
}
return stringBuilder.ToString(0, Math.Max(0, stringBuilder.Length - 2));
};
}
}
internal class StringArray_TypeConverter : TypeConverter
{
public StringArray_TypeConverter()
{
((TypeConverter)this).ConvertToObject = (string input, Type type) => (type != typeof(string[])) ? new string[0] : JsonConvert.DeserializeObject<string[]>(input);
((TypeConverter)this).ConvertToString = (object input, Type type) => (type != typeof(string[])) ? "[]" : JsonConvert.SerializeObject(input);
}
}
internal class Battery_TypeConverter : TypeConverter
{
public Battery_TypeConverter()
{
((TypeConverter)this).ConvertToObject = (string input, Type type) => (type != typeof(Battery)) ? ((object)new Battery(false, 1f)) : ((object)JsonConvert.DeserializeObject<Battery>(input));
((TypeConverter)this).ConvertToString = (object input, Type type) => (type != typeof(Battery)) ? JsonConvert.SerializeObject((object)new Battery(false, 1f)) : JsonConvert.SerializeObject(input);
}
}
internal class IntWithRarityArray_TypeConverter : TypeConverter
{
public IntWithRarityArray_TypeConverter()
{
((TypeConverter)this).ConvertToObject = delegate(string input, Type type)
{
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Expected O, but got Unknown
if (type != typeof(IntWithRarity[]))
{
return new IntWithRarity[0];
}
Dictionary<int, int> dictionary2 = JsonConvert.DeserializeObject<Dictionary<int, int>>(input);
List<IntWithRarity> list = new List<IntWithRarity>();
foreach (KeyValuePair<int, int> item in dictionary2)
{
list.Add(new IntWithRarity
{
id = item.Key,
rarity = item.Value
});
}
return list.ToArray();
};
((TypeConverter)this).ConvertToString = delegate(object input, Type type)
{
if (type != typeof(IntWithRarity[]))
{
return "{}";
}
Dictionary<int, int> dictionary = new Dictionary<int, int>();
IntWithRarity[] array = (IntWithRarity[])input;
foreach (IntWithRarity val in array)
{
dictionary.Add(val.id, val.rarity);
}
return JsonConvert.SerializeObject((object)dictionary);
};
}
}
internal class CompatibleNounArray_TypeConverter : TypeConverter
{
public CompatibleNounArray_TypeConverter()
{
((TypeConverter)this).ConvertToObject = delegate(string input, Type type)
{
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Expected O, but got Unknown
if (type != typeof(CompatibleNoun[]))
{
return new CompatibleNoun[0];
}
Dictionary<string, string> dictionary2 = JsonConvert.DeserializeObject<Dictionary<string, string>>(input);
List<CompatibleNoun> list = new List<CompatibleNoun>();
foreach (KeyValuePair<string, string> PAIR in dictionary2)
{
list.Add(new CompatibleNoun
{
noun = (from X in Resources.FindObjectsOfTypeAll<TerminalKeyword>()
where Utils.MakeFileNameSafe(((Object)X).name) == PAIR.Key
select X).FirstOrDefault(),
result = (from X in Resources.FindObjectsOfTypeAll<TerminalNode>()
where Utils.MakeFileNameSafe(((Object)X).name) == PAIR.Value
select X).FirstOrDefault()
});
}
return list.ToArray();
};
((TypeConverter)this).ConvertToString = delegate(object input, Type type)
{
if (type != typeof(CompatibleNoun[]))
{
return "{}";
}
Dictionary<string, string> NewOptions = new Dictionary<string, string>();
foreach (CompatibleNoun item in ((CompatibleNoun[])input).Where((CompatibleNoun x) => (Object)(object)x.noun != (Object)null && !NewOptions.ContainsKey(((Object)x.noun).name)))
{
Dictionary<string, string> dictionary = NewOptions;
string name = ((Object)item.noun).name;
TerminalNode result = item.result;
dictionary.Add(name, ((result != null) ? ((Object)result).name : null) ?? "");
}
return JsonConvert.SerializeObject((object)NewOptions);
};
}
}
internal class TerminalKeyword_TypeConverter : TypeConverter
{
public TerminalKeyword_TypeConverter()
{
((TypeConverter)this).ConvertToObject = (string input, Type type) => (type != typeof(TerminalKeyword)) ? ((object)ScriptableObject.CreateInstance<TerminalKeyword>()) : ((object)(from X in Resources.FindObjectsOfTypeAll<TerminalKeyword>()
where Utils.MakeFileNameSafe(((Object)X).name) == input
select X).FirstOrDefault());
((TypeConverter)this).ConvertToString = (object input, Type type) => (type != typeof(TerminalKeyword)) ? "" : ((Object)(TerminalKeyword)input).name;
}
}
internal class TerminalNode_TypeConverter : TypeConverter
{
public TerminalNode_TypeConverter()
{
((TypeConverter)this).ConvertToObject = (string input, Type type) => (type != typeof(TerminalNode)) ? ((object)ScriptableObject.CreateInstance<TerminalNode>()) : ((object)(from X in Resources.FindObjectsOfTypeAll<TerminalNode>()
where Utils.MakeFileNameSafe(((Object)X).name) == input
select X).FirstOrDefault());
((TypeConverter)this).ConvertToString = (object input, Type type) => (type != typeof(TerminalNode)) ? "" : ((Object)(TerminalNode)input).name;
}
}
internal class SpawnableEnemyWithRarityArray_TypeConverter : TypeConverter
{
public SpawnableEnemyWithRarityArray_TypeConverter()
{
((TypeConverter)this).ConvertToObject = delegate(string input, Type type)
{
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_0098: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: Expected O, but got Unknown
if (type != typeof(SpawnableEnemyWithRarity[]))
{
return new SpawnableEnemyWithRarity[0];
}
Dictionary<string, int> dictionary2 = JsonConvert.DeserializeObject<Dictionary<string, int>>(input);
List<SpawnableEnemyWithRarity> list = new List<SpawnableEnemyWithRarity>();
foreach (KeyValuePair<string, int> PAIR in dictionary2)
{
EnemyType val2 = (from X in Resources.FindObjectsOfTypeAll<EnemyType>()
where Utils.MakeFileNameSafe(X.enemyName) == PAIR.Key
select X).FirstOrDefault();
if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)null))
{
list.Add(new SpawnableEnemyWithRarity
{
enemyType = val2,
rarity = PAIR.Value
});
}
}
return list.ToArray();
};
((TypeConverter)this).ConvertToString = delegate(object input, Type type)
{
if (type != typeof(SpawnableEnemyWithRarity[]))
{
return "{}";
}
Dictionary<string, int> dictionary = new Dictionary<string, int>();
SpawnableEnemyWithRarity[] array = (SpawnableEnemyWithRarity[])input;
foreach (SpawnableEnemyWithRarity val in array)
{
string text = val.enemyType?.enemyName;
if (text != null && text != null)
{
if (dictionary.ContainsKey(text))
{
dictionary[text] += val.rarity;
}
else
{
dictionary.Add(text, val.rarity);
}
}
}
return JsonConvert.SerializeObject((object)dictionary);
};
}
}
internal class SpawnableItemWithRarityArray_TypeConverter : TypeConverter
{
public SpawnableItemWithRarityArray_TypeConverter()
{
((TypeConverter)this).ConvertToObject = delegate(string input, Type type)
{
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_0098: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: Expected O, but got Unknown
if (type != typeof(SpawnableItemWithRarity[]))
{
return new SpawnableItemWithRarity[0];
}
Dictionary<string, int> dictionary2 = JsonConvert.DeserializeObject<Dictionary<string, int>>(input);
List<SpawnableItemWithRarity> list = new List<SpawnableItemWithRarity>();
foreach (KeyValuePair<string, int> PAIR in dictionary2)
{
Item val2 = (from X in Resources.FindObjectsOfTypeAll<Item>()
where Utils.MakeFileNameSafe(X.itemName) == PAIR.Key
select X).FirstOrDefault();
if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)null))
{
list.Add(new SpawnableItemWithRarity
{
spawnableItem = val2,
rarity = PAIR.Value
});
}
}
return list.ToArray();
};
((TypeConverter)this).ConvertToString = delegate(object input, Type type)
{
if (type != typeof(SpawnableItemWithRarity[]))
{
return "{}";
}
Dictionary<string, int> dictionary = new Dictionary<string, int>();
SpawnableItemWithRarity[] array = (SpawnableItemWithRarity[])input;
foreach (SpawnableItemWithRarity val in array)
{
string text = val.spawnableItem?.itemName;
if (text != null && text != null)
{
if (dictionary.ContainsKey(text))
{
dictionary[text] += val.rarity;
}
else
{
dictionary.Add(text, val.rarity);
}
}
}
return JsonConvert.SerializeObject((object)dictionary);
};
}
}
internal class SpawnableEnemyWithRarityList_TypeConverter : TypeConverter
{
public SpawnableEnemyWithRarityList_TypeConverter()
{
((TypeConverter)this).ConvertToObject = delegate(string input, Type type)
{
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: Unknown result type (might be due to invalid IL or missing references)
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_00ae: Expected O, but got Unknown
if (type != typeof(List<SpawnableEnemyWithRarity>))
{
return new List<SpawnableEnemyWithRarity>();
}
Dictionary<string, int> dictionary2 = JsonConvert.DeserializeObject<Dictionary<string, int>>(input);
List<SpawnableEnemyWithRarity> list = new List<SpawnableEnemyWithRarity>();
foreach (KeyValuePair<string, int> PAIR in dictionary2)
{
EnemyType val = (from X in Resources.FindObjectsOfTypeAll<EnemyType>()
where Utils.MakeFileNameSafe(X.enemyName) == PAIR.Key
select X).FirstOrDefault();
if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)null))
{
list.Add(new SpawnableEnemyWithRarity
{
enemyType = val,
rarity = PAIR.Value
});
}
}
return list;
};
((TypeConverter)this).ConvertToString = delegate(object input, Type type)
{
if (type != typeof(List<SpawnableEnemyWithRarity>))
{
return "{}";
}
Dictionary<string, int> dictionary = new Dictionary<string, int>();
foreach (SpawnableEnemyWithRarity item in (List<SpawnableEnemyWithRarity>)input)
{
string text = item.enemyType?.enemyName;
if (text != null && text != null)
{
if (dictionary.ContainsKey(text))
{
dictionary[text] += item.rarity;
}
else
{
dictionary.Add(text, item.rarity);
}
}
}
return JsonConvert.SerializeObject((object)dictionary);
};
}
}
internal class SpawnableItemWithRarityList_TypeConverter : TypeConverter
{
public SpawnableItemWithRarityList_TypeConverter()
{
((TypeConverter)this).ConvertToObject = delegate(string input, Type type)
{
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: Unknown result type (might be due to invalid IL or missing references)
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_00ae: Expected O, but got Unknown
if (type != typeof(List<SpawnableItemWithRarity>))
{
return new List<SpawnableItemWithRarity>();
}
Dictionary<string, int> dictionary2 = JsonConvert.DeserializeObject<Dictionary<string, int>>(input);
List<SpawnableItemWithRarity> list = new List<SpawnableItemWithRarity>();
foreach (KeyValuePair<string, int> PAIR in dictionary2)
{
Item val = (from X in Resources.FindObjectsOfTypeAll<Item>()
where Utils.MakeFileNameSafe(X.itemName) == PAIR.Key
select X).FirstOrDefault();
if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)null))
{
list.Add(new SpawnableItemWithRarity
{
spawnableItem = val,
rarity = PAIR.Value
});
}
}
return list;
};
((TypeConverter)this).ConvertToString = delegate(object input, Type type)
{
if (type != typeof(List<SpawnableItemWithRarity>))
{
return "{}";
}
Dictionary<string, int> dictionary = new Dictionary<string, int>();
foreach (SpawnableItemWithRarity item in (List<SpawnableItemWithRarity>)input)
{
string text = item.spawnableItem?.itemName;
if (text != null && text != null)
{
if (dictionary.ContainsKey(text))
{
dictionary[text] += item.rarity;
}
else
{
dictionary.Add(text, item.rarity);
}
}
}
return JsonConvert.SerializeObject((object)dictionary);
};
}
}
internal class EnemyType_TypeConverter : TypeConverter
{
public EnemyType_TypeConverter()
{
((TypeConverter)this).ConvertToObject = (string input, Type type) => (type != typeof(EnemyType)) ? ((object)new EnemyType()) : ((object)(from X in Resources.FindObjectsOfTypeAll<EnemyType>()
where Utils.MakeFileNameSafe(X.enemyName) == input
select X).FirstOrDefault());
((TypeConverter)this).ConvertToString = (object input, Type type) => (type != typeof(EnemyType)) ? "" : ((EnemyType)input).enemyName;
}
}
internal class ItemGroupList_TypeConverter : TypeConverter
{
public ItemGroupList_TypeConverter()
{
((TypeConverter)this).ConvertToObject = delegate(string input, Type type)
{
if (type != typeof(List<ItemGroup>))
{
return new List<ItemGroup>();
}
List<ItemGroup> list2 = new List<ItemGroup>();
foreach (string item in JsonConvert.DeserializeObject<List<string>>(input))
{
ItemGroup val = ScriptableObject.CreateInstance<ItemGroup>();
((Object)val).name = item;
list2.Add(val);
}
return list2;
};
((TypeConverter)this).ConvertToString = delegate(object input, Type type)
{
if (type != typeof(List<ItemGroup>))
{
return "{}";
}
List<string> list = new List<string>();
foreach (ItemGroup item2 in (List<ItemGroup>)input)
{
list.Add(((Object)item2).name);
}
return JsonConvert.SerializeObject((object)list);
};
}
}
internal class RandomWeatherWithVariablesArray_TypeConverter : TypeConverter
{
public RandomWeatherWithVariablesArray_TypeConverter()
{
((TypeConverter)this).ConvertToObject = delegate(string input, Type type)
{
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
//IL_00b2: Expected O, but got Unknown
//IL_00b2: Expected O, but got I4
//IL_005e->IL005e: Incompatible stack types: O vs I4
//IL_005c->IL005e: Incompatible stack types: I4 vs O
//IL_005c->IL005e: Incompatible stack types: O vs I4
if (type != typeof(RandomWeatherWithVariables[]))
{
return new RandomWeatherWithVariables[0];
}
Dictionary<string, List<int>> dictionary2 = JsonConvert.DeserializeObject<Dictionary<string, List<int>>>(input);
List<RandomWeatherWithVariables> list = new List<RandomWeatherWithVariables>();
foreach (KeyValuePair<string, List<int>> item in dictionary2)
{
object obj = list;
? val2 = new RandomWeatherWithVariables();
val2 = val2;
int num;
if (!Enum.TryParse<LevelWeatherType>(item.Key, out LevelWeatherType result))
{
num = -1;
obj = num;
num = (int)obj;
}
else
{
obj = result;
num = (int)obj;
}
((RandomWeatherWithVariables)val2).weatherType = (LevelWeatherType)obj;
((RandomWeatherWithVariables)val2).weatherVariable = ((item.Value.Count > 0) ? item.Value[0] : 0);
((RandomWeatherWithVariables)val2).weatherVariable2 = ((item.Value.Count > 1) ? item.Value[1] : 0);
((List<RandomWeatherWithVariables>)num).Add((RandomWeatherWithVariables)val2);
}
return list.ToArray();
};
((TypeConverter)this).ConvertToString = delegate(object input, Type type)
{
if (type != typeof(RandomWeatherWithVariables[]))
{
return "{}";
}
Dictionary<string, List<int>> dictionary = new Dictionary<string, List<int>>();
RandomWeatherWithVariables[] array = (RandomWeatherWithVariables[])input;
foreach (RandomWeatherWithVariables val in array)
{
dictionary.Add(((object)(LevelWeatherType)(ref val.weatherType)).ToString(), new List<int>(2) { val.weatherVariable, val.weatherVariable2 });
}
return JsonConvert.SerializeObject((object)dictionary);
};
}
}
[Flags]
public enum ConfigBehavior
{
DoNotRun = 0,
ApplyExisting = 1,
CreateNewFiles = 2
}
[BepInPlugin("Kyxino.LethalEditor", "LethalEditor", "1.2.2")]
public class EditorMod : BaseUnityPlugin
{
public static ManualLogSource MLS = Logger.CreateLogSource("Kyxino.LethalEditor");
public static DirectoryInfo MainDir = Directory.CreateDirectory(Paths.BepInExRootPath + "\\LethalEditor");
public static ConfigFile LoadConfig = new ConfigFile(MainDir.FullName + "\\EditorSettings.cfg", saveOnInit: true, MetadataHelper.GetMetadata(typeof(EditorMod)));
public static ConfigEntry<bool> IgnoreOverlap = LoadConfig.Bind("Settings", "IgnoreOverlap", defaultValue: false, "When set to true, this WILL cause DefaultValues to be overwritten by non-Vanilla Values, but make Value more certain to apply.", 0);
public static ConfigBehavior BehaviorGrabbables = LoadConfig.Bind("Item Config Creation", "Grabbables", ConfigBehavior.ApplyExisting, "CreateNewFiles will allow files to be generated.\nApplyExisting allows existing files to run and potentially apply their settings.\nCreateNewFiles, ApplyExisting does both.\nBehavior for all GrabbableObjects configs.", 1).Value;
public static ConfigBehavior BehaviorItems = LoadConfig.Bind("Item Config Creation", "Items", ConfigBehavior.ApplyExisting, "Behavior for all Item configs.", 1).Value;
public static ConfigBehavior BehaviorSpecialItems = LoadConfig.Bind("Item Config Creation", "SpecialItems", ConfigBehavior.ApplyExisting, "Behavior for all special item classes configs.", 1).Value;
public static ConfigBehavior BehaviorEnemyAIs = LoadConfig.Bind("Enemy Config Creation", "EnemyAIs", ConfigBehavior.ApplyExisting, "Behavior for all EnemyAI configs.", 2).Value;
public static ConfigBehavior BehaviorEnemyTypes = LoadConfig.Bind("Enemy Config Creation", "EnemyTypes", ConfigBehavior.ApplyExisting, "Behavior for all EnemyType configs.", 2).Value;
public static ConfigBehavior BehaviorSpecialEnemies = LoadConfig.Bind("Enemy Config Creation", "SpecialEnemies", ConfigBehavior.ApplyExisting, "Behavior for all special enemy classes configs.", 2).Value;
public static ConfigBehavior BehaviorLevels = LoadConfig.Bind("Misc Config Creation", "Levels", ConfigBehavior.ApplyExisting, "Behavior for all SelectableLevel configs.").Value;
public static ConfigBehavior BehaviorUnlockableItems = LoadConfig.Bind("Misc Config Creation", "UnlockableItems", ConfigBehavior.ApplyExisting, "Behavior for all UnlockableItem configs.").Value;
public static ConfigBehavior BehaviorTerminalNodes = LoadConfig.Bind("Misc Config Creation", "TerminalNodes", ConfigBehavior.ApplyExisting, "Behavior for all TerminalNode configs.").Value;
public static ConfigBehavior BehaviorTerminalKeywords = LoadConfig.Bind("Misc Config Creation", "TerminalKeywords", ConfigBehavior.ApplyExisting, "Behavior for all TerminalKeyword configs.").Value;
public static Dictionary<Type, List<string>> FilterSettings = new Dictionary<Type, List<string>>
{
[typeof(GrabbableObject)] = new List<string>(17)
{
"isHeld", "isHeldByEnemy", "hasHitGround", "itemUsedUp", "isPocketed", "isBeingUsed", "isInElevator", "isInShipRoom", "isInFactory", "wasOwnerLastFrame",
"heldByPlayerOnServer", "reachedFloorTarget", "targetFloorPosition", "startFallingPosition", "currentUseCooldown", "fallTime", "scrapPersistedThroughRounds"
},
[typeof(SelectableLevel)] = new List<string>(3) { "currentWeather", "minTotalScrapValue", "maxTotalScrapValue" },
[typeof(EnemyType)] = new List<string>(1) { "numberSpawned" },
[typeof(EnemyAI)] = new List<string>(18)
{
"currentBehaviourStateIndex", "previousBehaviourStateIndex", "isInsidePlayerShip", "inSpecialAnimation", "thisEnemyIndex", "isClientCalculatingAI", "movingTowardsTargetPlayer", "moveTowardsDestination", "destination", "addPlayerVelocityToDestination",
"timeSinceSpawn", "ventAnimationFinished", "isEnemyDead", "daytimeEnemyLeaving", "stunnedIndefinitely", "stunNormalizedTimer", "postStunInvincibilityTimer", "isOutside"
},
[typeof(BlobAI)] = new List<string>(1) { "currentSlimeRange" },
[typeof(UnlockableItem)] = new List<string>(5) { "hasBeenMoved", "placedPosition", "placedRotation", "inStorage", "hasBeenUnlockedByPlayer" }
};
public static bool AllowFileCreation = false;
private static List<object> ObjectApplied = new List<object>();
public static IEnumerable<Type> LethalCompanyClasses = from CheckType in Assembly.GetAssembly(typeof(GrabbableObject)).GetTypes()
where CheckType.IsClass && !CheckType.IsAbstract
select CheckType;
private static readonly object LOCKERBOI = new object();
private void Awake()
{
Utils.AddAllTypes();
SceneManager.sceneLoaded += delegate(Scene scene, LoadSceneMode mode)
{
AllowFileCreation = (Object.op_Implicit((Object)(object)GameObject.Find("NetworkManager")) && NetworkManager.Singleton.IsHost) || ((Scene)(ref scene)).name == "InitSceneLaunchOptions" || ((Scene)(ref scene)).name == "InitScene" || ((Scene)(ref scene)).name == "MainMenu";
MLS.LogWarning((object)$"Scene changed: {((Scene)(ref scene)).name} ({((Scene)(ref scene)).path}) - Allow file creation? {AllowFileCreation}");
MLS.LogInfo((object)"Attempting to apply settings.");
try
{
Stopwatch stopwatch = Stopwatch.StartNew();
foreach (Type item in LethalCompanyClasses.Where((Type CheckType) => CheckType.IsSubclassOf(typeof(GrabbableObject))))
{
SaveCustom(item, "Items\\{GrabbableObject.itemName}\\{TypeName}Settings", BehaviorSpecialItems);
}
SaveCustom(typeof(GrabbableObject), "Items\\{GrabbableObject.itemName}\\GrabbableSettings", BehaviorGrabbables);
SaveCustom(typeof(Item), "Items\\{itemName}\\ItemSettings", BehaviorItems);
foreach (Type item2 in LethalCompanyClasses.Where((Type CheckType) => CheckType.IsSubclassOf(typeof(EnemyAI))))
{
SaveCustom(item2, "Enemies\\{EnemyAI.enemyName}\\{TypeName}Settings", BehaviorSpecialEnemies);
}
SaveCustom(typeof(EnemyAI), "Enemies\\{EnemyAI.enemyName}\\EnemyAISettings", BehaviorEnemyAIs);
SaveCustom(typeof(EnemyType), "Enemies\\{enemyName}\\EnemyTypeSettings", BehaviorEnemyTypes);
SaveCustom(typeof(SelectableLevel), "Maps\\{PlanetName}\\MapSettings", BehaviorLevels);
SaveCustom(typeof(UnlockableItem), "UnlockableItems\\{unlockableName}\\UnlockableItemSettings", BehaviorUnlockableItems, Resources.FindObjectsOfTypeAll<UnlockablesList>().SelectMany((UnlockablesList x) => x.unlockables));
SaveCustom(typeof(TerminalNode), "TerminalNode\\{name}", BehaviorTerminalNodes);
SaveCustom(typeof(TerminalKeyword), "TerminalKeywords\\{name}", BehaviorTerminalKeywords);
MLS.LogInfo((object)$"Done applying settings. ({(float)stopwatch.ElapsedTicks / 10000f:000.0000}ms)");
}
catch (Exception ex)
{
MLS.LogWarning((object)"Failed to apply settings.");
MLS.LogWarning((object)ex);
}
};
}
public static string ReplaceIfPresent(string ModifyingPath, string StringToReplace, Func<object, string> GetReplacement, object CopyObject = null)
{
if (!ModifyingPath.Contains(StringToReplace))
{
return ModifyingPath;
}
string text = Utils.MakeFileNameSafe(GetReplacement(CopyObject));
if (Utility.IsNullOrWhiteSpace(text))
{
return ModifyingPath;
}
return ModifyingPath.Replace(StringToReplace, text);
}
private static void SaveCustom(Type SaveType, string Path, ConfigBehavior Behavior, IEnumerable<object> CustomLookup = null)
{
//IL_011c: Unknown result type (might be due to invalid IL or missing references)
//IL_0121: Unknown result type (might be due to invalid IL or missing references)
if (Behavior == ConfigBehavior.DoNotRun)
{
return;
}
lock (LOCKERBOI)
{
FieldInfo[] fields = SaveType.GetFields(BindingFlags.Instance | BindingFlags.Public);
Path = ReplaceIfPresent(Path, "{TypeName}", (object CopyObject) => SaveType.Name);
foreach (object item in (CustomLookup ?? Resources.FindObjectsOfTypeAll(SaveType)).Where((object x) => !ObjectApplied.Contains(x)))
{
if (item == null)
{
MLS.LogWarning((object)$"Missing object class: {item} {SaveType}");
continue;
}
if (!IgnoreOverlap.Value)
{
ObjectApplied.Add(item);
}
string text = Path;
try
{
object obj;
if (!SaveType.IsAssignableFrom(typeof(Object)))
{
obj = "";
}
else
{
Object val = (Object)item;
obj = (((int)val != 0) ? val.name : null);
}
string Name = (string)obj;
text = ReplaceIfPresent(text, "{name}", (object CopyObject) => Name, item);
text = ReplaceIfPresent(text, "{PlanetName}", delegate(object CopyObject)
{
//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)
SelectableLevel val6 = (SelectableLevel)CopyObject;
return (((int)val6 != 0) ? val6.PlanetName : null) ?? Name;
}, item);
text = ReplaceIfPresent(text, "{GrabbableObject.itemName}", delegate(object CopyObject)
{
//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)
GrabbableObject val5 = (GrabbableObject)CopyObject;
return (((int)val5 == 0) ? null : val5.itemProperties?.itemName) ?? Name;
}, item);
text = ReplaceIfPresent(text, "{itemName}", delegate(object CopyObject)
{
//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)
Item val4 = (Item)CopyObject;
return (((int)val4 != 0) ? val4.itemName : null) ?? Name;
}, item);
text = ReplaceIfPresent(text, "{EnemyAI.enemyName}", delegate(object CopyObject)
{
//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)
EnemyAI val3 = (EnemyAI)CopyObject;
return (((int)val3 == 0) ? null : val3.enemyType?.enemyName) ?? Name;
}, item);
text = ReplaceIfPresent(text, "{enemyName}", delegate(object CopyObject)
{
//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)
EnemyType val2 = (EnemyType)CopyObject;
return (((int)val2 != 0) ? val2.enemyName : null) ?? Name;
}, item);
if ((!Behavior.HasFlag(ConfigBehavior.CreateNewFiles) || !AllowFileCreation) && !File.Exists(MainDir.FullName + "\\" + text + ".cfg"))
{
continue;
}
ConfigFile configFile = new ConfigFile(MainDir.FullName + "\\" + text + ".cfg", saveOnInit: false, MetadataHelper.GetMetadata(typeof(EditorMod)));
ConfigEntry<bool> configEntry = configFile.Bind("ACTIVE SETTINGS", "ConfigEnabled", defaultValue: false, "Whether or not this config file will apply.", 0);
configFile.Bind("ACTIVE SETTINGS", "SaveType", SaveType.Name, "The type of this config.", 0);
ConfigEntry<string[]> configEntry2 = configFile.Bind("ACTIVE SETTINGS", "LoadSettings", new string[0], "Settings that will load and apply to the game.\nEx: [\"SettingName\",\"OtherSettingName\"]", 0);
int num = 1;
string text2 = "SETTINGS";
FieldInfo[] array = fields;
foreach (FieldInfo fieldInfo in array)
{
foreach (CustomAttributeTypedArgument item2 in fieldInfo.CustomAttributes.Where((CustomAttributeData x) => x.AttributeType == typeof(HeaderAttribute)).SelectMany((CustomAttributeData Data) => Data.ConstructorArguments.ToList()))
{
num++;
text2 = item2.Value.ToString().ToUpper() ?? "";
}
if (fieldInfo.CustomAttributes.FirstOrDefault()?.AttributeType == typeof(HideInInspector) || fieldInfo.DeclaringType != SaveType || (FilterSettings.ContainsKey(SaveType) && FilterSettings[SaveType].Contains(fieldInfo.Name)) || !TomlTypeConverter.CanConvert(fieldInfo.FieldType))
{
continue;
}
object value = configFile.Bind(text2, fieldInfo.Name, fieldInfo.FieldType, fieldInfo.GetValue(item), fieldInfo.CustomAttributes.Where((CustomAttributeData x) => x.AttributeType == typeof(TooltipAttribute)).FirstOrDefault()?.ConstructorArguments.FirstOrDefault().Value?.ToString() ?? "", num).Value;
if (Behavior.HasFlag(ConfigBehavior.ApplyExisting) && configEntry.Value && configEntry2.Value.Contains(fieldInfo.Name))
{
if (value.GetType() != fieldInfo.FieldType)
{
MLS.LogWarning((object)(text + ".cfg > " + text2 + " > " + fieldInfo.Name + "'s input type (" + value.GetType().Name + ") is not the same as the required type: " + fieldInfo.FieldType.Name + "."));
return;
}
fieldInfo.SetValue(item, value);
}
}
configFile.Save();
}
catch (Exception arg)
{
MLS.LogWarning((object)$"Failed to apply settings to a specific object. Path: {MainDir.FullName}\\{text}\n{arg}");
}
}
}
}
}
}
namespace LethalEditor.Configuration
{
public sealed class SettingChangedEventArgs : EventArgs
{
public ConfigEntryBase ChangedSetting { get; }
public SettingChangedEventArgs(ConfigEntryBase changedSetting)
{
ChangedSetting = changedSetting;
base..ctor();
}
}
public class ConfigDescription
{
public string Description { get; } = description ?? throw new ArgumentNullException("description");
public AcceptableValueBase AcceptableValues { get; }
public object[] Tags { get; }
public static ConfigDescription Empty { get; } = new ConfigDescription("", null);
public ConfigDescription(string description, AcceptableValueBase acceptableValues = null, params object[] tags)
{
AcceptableValues = acceptableValues;
Tags = tags;
base..ctor();
}
}
public class ConfigDefinition : IEquatable<ConfigDefinition>
{
private static readonly char[] _invalidConfigChars = new char[8] { '=', '\n', '\t', '\\', '"', '\'', '[', ']' };
public int Order { get; }
public string Section { get; }
public string Key { get; }
public ConfigDefinition(string section, string key, int order = -1)
{
CheckInvalidConfigChars(section, "section");
CheckInvalidConfigChars(key, "key");
Order = order;
Key = key;
Section = section;
}
private static void CheckInvalidConfigChars(string val, string name)
{
if (val == null)
{
throw new ArgumentNullException(name);
}
if (val != val.Trim())
{
throw new ArgumentException("Cannot use whitespace characters at start or end of section and key names", name);
}
if (val.Any((char c) => _invalidConfigChars.Contains(c)))
{
throw new ArgumentException("Cannot use any of the following characters in section and key names: = \\n \\t \\ \" ' [ ]", name);
}
}
public bool Equals(ConfigDefinition other)
{
return other != null && string.Equals(Key, other.Key) && string.Equals(Section, other.Section);
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (this == (ConfigDefinition)obj)
{
return true;
}
return Equals(obj as ConfigDefinition);
}
public override int GetHashCode()
{
return (((Key != null) ? Key.GetHashCode() : 0) * 397) ^ ((Section != null) ? Section.GetHashCode() : 0);
}
public static bool operator ==(ConfigDefinition left, ConfigDefinition right)
{
return object.Equals(left, right);
}
public static bool operator !=(ConfigDefinition left, ConfigDefinition right)
{
return !object.Equals(left, right);
}
public override string ToString()
{
return Section + "." + Key;
}
}
public abstract class ConfigEntryBase
{
public ConfigFile ConfigFile { get; }
public ConfigDefinition Definition { get; }
public ConfigDescription Description { get; }
public Type SettingType { get; }
public object DefaultValue { get; }
public abstract object BoxedValue { get; set; }
internal ConfigEntryBase(ConfigFile configFile, ConfigDefinition definition, Type settingType, object defaultValue, ConfigDescription configDescription)
{
ConfigFile = configFile ?? throw new ArgumentNullException("configFile");
Definition = definition ?? throw new ArgumentNullException("definition");
SettingType = settingType ?? throw new ArgumentNullException("settingType");
Description = configDescription ?? ConfigDescription.Empty;
if (Description.AcceptableValues != null && !SettingType.IsAssignableFrom(Description.AcceptableValues.ValueType))
{
throw new ArgumentException("configDescription.AcceptableValues is for a different type than the type of this setting");
}
DefaultValue = defaultValue;
BoxedValue = defaultValue;
}
public string GetSerializedValue()
{
return TomlTypeConverter.ConvertToString(BoxedValue, SettingType);
}
public void SetSerializedValue(string value)
{
try
{
object boxedValue = TomlTypeConverter.ConvertToValue(value, SettingType);
BoxedValue = boxedValue;
}
catch (Exception ex)
{
EditorMod.MLS.Log((LogLevel)4, (object)$"Config value of setting \"{Definition}\" could not be parsed and will be ignored. Reason: {ex.Message}; Value: {value}");
}
}
protected T ClampValue<T>(T value)
{
if (Description.AcceptableValues != null)
{
return (T)Description.AcceptableValues.Clamp((object)value);
}
return value;
}
protected void OnSettingChanged(object sender)
{
ConfigFile.OnSettingChanged(sender, this);
}
public void WriteDescription(StreamWriter writer)
{
if (!string.IsNullOrEmpty(Description.Description))
{
writer.WriteLine("## " + Description.Description.Replace("\n", "\n## "));
}
string text = ((typeof(List<>).Name == SettingType.Name && SettingType.GenericTypeArguments.Length != 0) ? ("List<" + SettingType.GenericTypeArguments[0].Name + ">") : SettingType.Name);
writer.WriteLine("# Setting type: " + text);
writer.WriteLine("# Default value: " + TomlTypeConverter.ConvertToString(DefaultValue, SettingType));
if (Description.AcceptableValues != null)
{
writer.WriteLine(Description.AcceptableValues.ToDescriptionString());
}
else if (SettingType.IsEnum)
{
writer.WriteLine("# Acceptable values: " + string.Join(", ", Enum.GetNames(SettingType)));
if (SettingType.GetCustomAttributes(typeof(FlagsAttribute), inherit: true).Any())
{
writer.WriteLine("# Multiple values can be set at the same time by separating them with , (e.g. Debug, Warning)");
}
}
}
}
public sealed class ConfigEntry<T> : ConfigEntryBase
{
private T _typedValue;
public T Value
{
get
{
return _typedValue;
}
set
{
value = ClampValue(value);
if (!object.Equals(_typedValue, value))
{
_typedValue = value;
OnSettingChanged(this);
}
}
}
public override object BoxedValue
{
get
{
return Value;
}
set
{
Value = (T)value;
}
}
public event EventHandler SettingChanged;
internal ConfigEntry(ConfigFile configFile, ConfigDefinition definition, T defaultValue, ConfigDescription configDescription)
: base(configFile, definition, typeof(T), defaultValue, configDescription)
{
configFile.SettingChanged += delegate(object sender, SettingChangedEventArgs args)
{
if (args.ChangedSetting == this)
{
this.SettingChanged?.Invoke(sender, args);
}
};
}
internal ConfigEntry(ConfigFile configFile, ConfigDefinition definition, Type settingType, object defaultValue, ConfigDescription configDescription)
: base(configFile, definition, settingType, defaultValue, configDescription)
{
configFile.SettingChanged += delegate(object sender, SettingChangedEventArgs args)
{
if (args.ChangedSetting == this)
{
this.SettingChanged?.Invoke(sender, args);
}
};
}
}
public class ConfigFile : IDictionary<ConfigDefinition, ConfigEntryBase>, ICollection<KeyValuePair<ConfigDefinition, ConfigEntryBase>>, IEnumerable<KeyValuePair<ConfigDefinition, ConfigEntryBase>>, IEnumerable
{
private readonly BepInPlugin _ownerMetadata;
private readonly object _ioLock = new object();
internal static ConfigFile CoreConfig { get; } = new ConfigFile(Paths.BepInExConfigPath, saveOnInit: true);
protected Dictionary<ConfigDefinition, ConfigEntryBase> Entries { get; } = new Dictionary<ConfigDefinition, ConfigEntryBase>();
private Dictionary<ConfigDefinition, string> OrphanedEntries { get; } = new Dictionary<ConfigDefinition, string>();
public string ConfigFilePath { get; }
public bool SaveOnConfigSet { get; set; } = true;
public int Count
{
get
{
lock (_ioLock)
{
return Entries.Count;
}
}
}
public bool IsReadOnly => false;
ConfigEntryBase IDictionary<ConfigDefinition, ConfigEntryBase>.this[ConfigDefinition key]
{
get
{
lock (_ioLock)
{
return Entries[key];
}
}
set
{
throw new InvalidOperationException("Directly setting a config entry is not supported");
}
}
public ConfigEntryBase this[ConfigDefinition key]
{
get
{
lock (_ioLock)
{
return Entries[key];
}
}
}
public ConfigEntryBase this[string section, string key] => this[new ConfigDefinition(section, key)];
public ICollection<ConfigDefinition> Keys
{
get
{
lock (_ioLock)
{
return Entries.Keys.ToArray();
}
}
}
ICollection<ConfigEntryBase> IDictionary<ConfigDefinition, ConfigEntryBase>.Values
{
get
{
lock (_ioLock)
{
return Entries.Values.ToArray();
}
}
}
public event EventHandler ConfigReloaded;
public event EventHandler<SettingChangedEventArgs> SettingChanged;
public ConfigFile(string configPath, bool saveOnInit)
: this(configPath, saveOnInit, null)
{
}
public ConfigFile(string configPath, bool saveOnInit, BepInPlugin ownerMetadata)
{
_ownerMetadata = ownerMetadata;
if (configPath == null)
{
throw new ArgumentNullException("configPath");
}
configPath = Path.GetFullPath(configPath);
ConfigFilePath = configPath;
if (File.Exists(ConfigFilePath))
{
Reload();
}
else if (saveOnInit)
{
Save();
}
}
public void Reload()
{
lock (_ioLock)
{
OrphanedEntries.Clear();
string section = string.Empty;
string[] array = File.ReadAllLines(ConfigFilePath);
for (int i = 0; i < array.Length; i++)
{
string text = array[i].Trim();
if (text.StartsWith("#"))
{
continue;
}
if (text.StartsWith("[") && text.EndsWith("]"))
{
string text2 = text;
section = text2.Substring(1, text2.Length - 1 - 1);
continue;
}
string[] array2 = text.Split(new char[1] { '=' }, 2);
if (array2.Length == 2)
{
string key = array2[0].Trim();
string text3 = array2[1].Trim();
ConfigDefinition key2 = new ConfigDefinition(section, key);
Entries.TryGetValue(key2, out var value);
if (value != null)
{
value.SetSerializedValue(text3);
}
else
{
OrphanedEntries[key2] = text3;
}
}
}
}
OnConfigReloaded();
}
public void Save()
{
lock (_ioLock)
{
string directoryName = Path.GetDirectoryName(ConfigFilePath);
if (directoryName != null)
{
Directory.CreateDirectory(directoryName);
}
using StreamWriter streamWriter = new StreamWriter(ConfigFilePath, append: false, Utility.UTF8NoBom);
if (_ownerMetadata != null)
{
streamWriter.WriteLine($"## Settings file was created by plugin {_ownerMetadata.Name} v{_ownerMetadata.Version}");
streamWriter.WriteLine("## Plugin GUID: " + _ownerMetadata.GUID);
streamWriter.WriteLine();
}
foreach (var item in from x in Entries.Select((KeyValuePair<ConfigDefinition, ConfigEntryBase> x) => new
{
Key = x.Key,
entry = x.Value,
value = x.Value.GetSerializedValue()
}).Concat(OrphanedEntries.Select((KeyValuePair<ConfigDefinition, string> x) => new
{
Key = x.Key,
entry = (ConfigEntryBase)null,
value = x.Value
}))
group x by (x.Key.Order, x.Key.Section) into x
orderby x.Key.Order == -1, x.Key.Order, x.Key.Section
select x)
{
streamWriter.WriteLine("[" + item.Key.Item2 + "]");
foreach (var item2 in item)
{
streamWriter.WriteLine();
item2.entry?.WriteDescription(streamWriter);
streamWriter.WriteLine(item2.Key.Key + " = " + item2.value);
}
streamWriter.WriteLine();
}
}
}
public bool TryGetEntry<T>(ConfigDefinition configDefinition, out ConfigEntry<T> entry)
{
lock (_ioLock)
{
if (Entries.TryGetValue(configDefinition, out var value))
{
entry = (ConfigEntry<T>)value;
return true;
}
entry = null;
return false;
}
}
public bool TryGetEntry<T>(string section, string key, out ConfigEntry<T> entry)
{
return TryGetEntry(new ConfigDefinition(section, key), out entry);
}
public ConfigEntry<T> Bind<T>(ConfigDefinition configDefinition, Type settingType, T defaultValue, ConfigDescription configDescription = null)
{
if (!TomlTypeConverter.CanConvert(settingType))
{
throw new ArgumentException(string.Format("Type {0} is not supported by the config system. Supported types: {1}", settingType, string.Join(", ", (from x in TomlTypeConverter.GetSupportedTypes()
select x.Name).ToArray())));
}
lock (_ioLock)
{
if (Entries.TryGetValue(configDefinition, out var value))
{
return (ConfigEntry<T>)value;
}
ConfigEntry<T> configEntry = new ConfigEntry<T>(this, configDefinition, settingType, defaultValue, configDescription);
Entries[configDefinition] = configEntry;
if (OrphanedEntries.TryGetValue(configDefinition, out var value2))
{
configEntry.SetSerializedValue(value2);
OrphanedEntries.Remove(configDefinition);
}
if (SaveOnConfigSet)
{
Save();
}
return configEntry;
}
}
public ConfigEntry<T> Bind<T>(ConfigDefinition configDefinition, T defaultValue, ConfigDescription configDescription = null)
{
return Bind(configDefinition, typeof(T), defaultValue, configDescription);
}
public ConfigEntry<T> Bind<T>(string section, string key, T defaultValue, ConfigDescription configDescription = null, int order = -1)
{
return Bind(new ConfigDefinition(section, key, order), defaultValue, configDescription);
}
public ConfigEntry<T> Bind<T>(string section, string key, Type settingType, T defaultValue, ConfigDescription configDescription = null, int order = -1)
{
return Bind(new ConfigDefinition(section, key, order), settingType, defaultValue, configDescription);
}
public ConfigEntry<T> Bind<T>(string section, string key, T defaultValue, string description, int order = -1)
{
return Bind(new ConfigDefinition(section, key, order), defaultValue, new ConfigDescription(description, null));
}
public ConfigEntry<T> Bind<T>(string section, string key, Type settingType, T defaultValue, string description, int order = -1)
{
return Bind(new ConfigDefinition(section, key, order), settingType, defaultValue, new ConfigDescription(description, null));
}
internal void OnSettingChanged(object sender, ConfigEntryBase changedEntryBase)
{
if (changedEntryBase == null)
{
throw new ArgumentNullException("changedEntryBase");
}
if (SaveOnConfigSet)
{
Save();
}
EventHandler<SettingChangedEventArgs> settingChanged = this.SettingChanged;
if (settingChanged == null)
{
return;
}
SettingChangedEventArgs e = new SettingChangedEventArgs(changedEntryBase);
foreach (EventHandler<SettingChangedEventArgs> item in settingChanged.GetInvocationList().Cast<EventHandler<SettingChangedEventArgs>>())
{
try
{
item(sender, e);
}
catch (Exception ex)
{
EditorMod.MLS.Log((LogLevel)2, (object)ex);
}
}
}
private void OnConfigReloaded()
{
EventHandler configReloaded = this.ConfigReloaded;
if (configReloaded == null)
{
return;
}
foreach (EventHandler item in configReloaded.GetInvocationList().Cast<EventHandler>())
{
try
{
item(this, EventArgs.Empty);
}
catch (Exception ex)
{
EditorMod.MLS.Log((LogLevel)2, (object)ex);
}
}
}
public IEnumerator<KeyValuePair<ConfigDefinition, ConfigEntryBase>> GetEnumerator()
{
return Entries.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
void ICollection<KeyValuePair<ConfigDefinition, ConfigEntryBase>>.Add(KeyValuePair<ConfigDefinition, ConfigEntryBase> item)
{
lock (_ioLock)
{
Entries.Add(item.Key, item.Value);
}
}
public bool Contains(KeyValuePair<ConfigDefinition, ConfigEntryBase> item)
{
lock (_ioLock)
{
return ((ICollection<KeyValuePair<ConfigDefinition, ConfigEntryBase>>)Entries).Contains(item);
}
}
void ICollection<KeyValuePair<ConfigDefinition, ConfigEntryBase>>.CopyTo(KeyValuePair<ConfigDefinition, ConfigEntryBase>[] array, int arrayIndex)
{
lock (_ioLock)
{
((ICollection<KeyValuePair<ConfigDefinition, ConfigEntryBase>>)Entries).CopyTo(array, arrayIndex);
}
}
bool ICollection<KeyValuePair<ConfigDefinition, ConfigEntryBase>>.Remove(KeyValuePair<ConfigDefinition, ConfigEntryBase> item)
{
lock (_ioLock)
{
return Entries.Remove(item.Key);
}
}
public bool ContainsKey(ConfigDefinition key)
{
lock (_ioLock)
{
return Entries.ContainsKey(key);
}
}
public void Add(ConfigDefinition key, ConfigEntryBase value)
{
throw new InvalidOperationException("Directly adding a config entry is not supported");
}
public bool Remove(ConfigDefinition key)
{
lock (_ioLock)
{
return Entries.Remove(key);
}
}
public void Clear()
{
lock (_ioLock)
{
Entries.Clear();
}
}
bool IDictionary<ConfigDefinition, ConfigEntryBase>.TryGetValue(ConfigDefinition key, out ConfigEntryBase value)
{
lock (_ioLock)
{
return Entries.TryGetValue(key, out value);
}
}
}
}