Due to update 2.4.3, some mods may no longer function. FixedConfig may be necessary.
Decompiled source of MapPackLoader v1.0.2
MapPackLoader.dll
Decompiled a week agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using Microsoft.CodeAnalysis; using MiniJSON; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.6", FrameworkDisplayName = ".NET Framework 4.6")] [assembly: AssemblyCompany("MapPackLoader")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("My first plugin")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("MapPackLoader")] [assembly: AssemblyTitle("MapPackLoader")] [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 MapPackLoader { [BepInPlugin("com.kijetesantakalu912345.MapPackLoader", "MapPackLoader", "1.0.0")] public class Plugin : BaseUnityPlugin { public static string startTimeString = DateTime.Now.ToString("yyyy-MMM-dd hhtt ss.fff"); public void Awake() { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin MapPackLoader is loaded!"); List<string> list = RecursivelySearchDirectoryForFile(Paths.PluginPath, "mappack.zip"); if (list.Count == 0) { ((BaseUnityPlugin)this).Logger.LogError((object)"No mappack.zip found! map pack loader will not load any map pack."); return; } if (list.Count > 1) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("multiple `mappack.zip`s found! The mappack.zip at `" + list[0] + "` will be used. paths of all map packs:")); string text = ""; foreach (string item in list) { text = text + item + "\n"; } ((BaseUnityPlugin)this).Logger.LogWarning((object)text); } string archiveFileName = list[0]; ZipArchive val = ZipFile.OpenRead(archiveFileName); try { string text2 = Path.Combine(Paths.PluginPath, "Maps"); ((BaseUnityPlugin)this).Logger.LogInfo((object)("maps folder: " + text2)); if (!Directory.Exists(text2)) { Directory.CreateDirectory(text2); } CheckAndUpdateOldMaps(val, text2); } finally { ((IDisposable)val)?.Dispose(); } } public static List<string> RecursivelySearchDirectoryForFile(string searchPath, string containedFileName) { List<string> list = new List<string>(); string[] files = Directory.GetFiles(searchPath); for (int i = 0; i < files.Count(); i++) { if (Path.GetFileName(files[i]).Contains(containedFileName)) { list.Add(files[i]); } } string[] directories = Directory.GetDirectories(searchPath); for (int j = 0; j < directories.Count(); j++) { list.AddRange(RecursivelySearchDirectoryForFile(directories[j], containedFileName)); } return list; } public void CheckAndUpdateOldMaps(ZipArchive mapPackZip, string mapsFolderPath) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Expected O, but got Unknown Dictionary<string, ZippedMap> dictionary = new Dictionary<string, ZippedMap>(); for (int i = 0; i < mapPackZip.Entries.Count; i++) { ZipArchive val = new ZipArchive(mapPackZip.Entries[i].Open()); ZipArchiveEntry val2 = null; val2 = val.GetEntry("MetaData.json"); if (val2 == null) { throw new Exception("Invalid map \"" + mapPackZip.Entries[i].FullName + "\" in the map pack has no MetaData.json file. Map pack not extracted."); } string json = new StreamReader(val2.Open()).ReadToEnd(); Dictionary<string, object> dictionary2 = Json.Deserialize(json) as Dictionary<string, object>; string text = dictionary2["MapName"].ToString(); uint version = Convert.ToUInt32(dictionary2["MapVersion"]); dictionary.Add(text, new ZippedMap(text, version, val, mapPackZip.Entries[i].Name)); } for (int j = 0; j < Directory.GetFiles(mapsFolderPath).Length; j++) { string text2 = Directory.GetFiles(mapsFolderPath)[j]; if (Path.GetExtension(text2) != ".zip") { continue; } ZipArchive val3 = new ZipArchive((Stream)File.OpenRead(text2)); try { ZipArchiveEntry val4 = null; val4 = val3.GetEntry("MetaData.json"); if (val4 == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Invalid map \"" + mapPackZip.Entries[j].FullName + "\" in your maps folder has no MetaData.json, moving...")); MoveMapToNewFolder(mapsFolderPath, text2); continue; } string json2 = new StreamReader(val4.Open()).ReadToEnd(); Dictionary<string, object> dictionary3 = Json.Deserialize(json2) as Dictionary<string, object>; string key = dictionary3["MapName"].ToString(); uint num = Convert.ToUInt32(dictionary3["MapVersion"]); if (dictionary.ContainsKey(key)) { if (dictionary[key].version != num) { val3.Dispose(); MoveMapToNewFolder(mapsFolderPath, text2); ExtractMapZipFromMainZip(mapsFolderPath, mapPackZip, dictionary[key].mapFileName); } dictionary[key].zip.Dispose(); dictionary.Remove(key); } else { val3.Dispose(); MoveMapToNewFolder(mapsFolderPath, text2); } } finally { ((IDisposable)val3)?.Dispose(); } } foreach (ZippedMap value in dictionary.Values) { ExtractMapZipFromMainZip(mapsFolderPath, mapPackZip, value.mapFileName); value.zip.Dispose(); } } public void ExtractMapZipFromMainZip(string mapsFolderPath, ZipArchive mapPackZip, string mapFileName) { string destinationFileName = Path.Combine(mapsFolderPath, mapFileName); mapPackZip.GetEntry(mapFileName).ExtractToFile(destinationFileName); } public void MoveMapToNewFolder(string mapsFolder, string mapPath) { string text = Path.Combine(Directory.GetParent(mapsFolder).FullName, "maps moved when setting up map pack " + startTimeString); if (!Directory.Exists(text)) { Directory.CreateDirectory(text); } ((BaseUnityPlugin)this).Logger.LogInfo((object)Path.Combine(text + "/" + Path.GetFileName(mapPath))); File.Move(mapPath, Path.Combine(text + "/" + Path.GetFileName(mapPath))); } } public struct ZippedMap { public string mapName; public string mapFileName; public uint version; public ZipArchive zip; public ZippedMap(string mapName, uint version, ZipArchive zip, string mapFileName) { this.mapName = mapName; this.version = version; this.zip = zip; this.mapFileName = mapFileName; } } public static class PluginInfo { public const string PLUGIN_GUID = "MapPackLoader"; public const string PLUGIN_NAME = "MapPackLoader"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace MiniJSON { public static class Json { private sealed class Parser : IDisposable { private enum TOKEN { NONE, CURLY_OPEN, CURLY_CLOSE, SQUARED_OPEN, SQUARED_CLOSE, COLON, COMMA, STRING, NUMBER, TRUE, FALSE, NULL } private const string WORD_BREAK = "{}[],:\""; private StringReader json; private char PeekChar => Convert.ToChar(json.Peek()); private char NextChar => Convert.ToChar(json.Read()); private string NextWord { get { StringBuilder stringBuilder = new StringBuilder(); while (!IsWordBreak(PeekChar)) { stringBuilder.Append(NextChar); if (json.Peek() == -1) { break; } } return stringBuilder.ToString(); } } private TOKEN NextToken { get { EatWhitespace(); if (json.Peek() == -1) { return TOKEN.NONE; } switch (PeekChar) { case '{': return TOKEN.CURLY_OPEN; case '}': json.Read(); return TOKEN.CURLY_CLOSE; case '[': return TOKEN.SQUARED_OPEN; case ']': json.Read(); return TOKEN.SQUARED_CLOSE; case ',': json.Read(); return TOKEN.COMMA; case '"': return TOKEN.STRING; case ':': return TOKEN.COLON; case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return TOKEN.NUMBER; default: return NextWord switch { "false" => TOKEN.FALSE, "true" => TOKEN.TRUE, "null" => TOKEN.NULL, _ => TOKEN.NONE, }; } } } public static bool IsWordBreak(char c) { return char.IsWhiteSpace(c) || "{}[],:\"".IndexOf(c) != -1; } private Parser(string jsonString) { json = new StringReader(jsonString); } public static object Parse(string jsonString) { using Parser parser = new Parser(jsonString); return parser.ParseValue(); } public void Dispose() { json.Dispose(); json = null; } private Dictionary<string, object> ParseObject() { Dictionary<string, object> dictionary = new Dictionary<string, object>(); json.Read(); while (true) { switch (NextToken) { case TOKEN.NONE: return null; case TOKEN.CURLY_CLOSE: return dictionary; case TOKEN.COMMA: continue; } string text = ParseString(); if (text == null) { return null; } if (NextToken != TOKEN.COLON) { return null; } json.Read(); dictionary[text] = ParseValue(); } } private List<object> ParseArray() { List<object> list = new List<object>(); json.Read(); bool flag = true; while (flag) { TOKEN nextToken = NextToken; switch (nextToken) { case TOKEN.NONE: return null; case TOKEN.SQUARED_CLOSE: flag = false; break; default: { object item = ParseByToken(nextToken); list.Add(item); break; } case TOKEN.COMMA: break; } } return list; } private object ParseValue() { TOKEN nextToken = NextToken; return ParseByToken(nextToken); } private object ParseByToken(TOKEN token) { return token switch { TOKEN.STRING => ParseString(), TOKEN.NUMBER => ParseNumber(), TOKEN.CURLY_OPEN => ParseObject(), TOKEN.SQUARED_OPEN => ParseArray(), TOKEN.TRUE => true, TOKEN.FALSE => false, TOKEN.NULL => null, _ => null, }; } private string ParseString() { StringBuilder stringBuilder = new StringBuilder(); json.Read(); bool flag = true; while (flag) { if (json.Peek() == -1) { flag = false; break; } char nextChar = NextChar; switch (nextChar) { case '"': flag = false; break; case '\\': if (json.Peek() == -1) { flag = false; break; } nextChar = NextChar; switch (nextChar) { case '"': case '/': case '\\': stringBuilder.Append(nextChar); break; case 'b': stringBuilder.Append('\b'); break; case 'f': stringBuilder.Append('\f'); break; case 'n': stringBuilder.Append('\n'); break; case 'r': stringBuilder.Append('\r'); break; case 't': stringBuilder.Append('\t'); break; case 'u': { char[] array = new char[4]; for (int i = 0; i < 4; i++) { array[i] = NextChar; } stringBuilder.Append((char)Convert.ToInt32(new string(array), 16)); break; } } break; default: stringBuilder.Append(nextChar); break; } } return stringBuilder.ToString(); } private object ParseNumber() { string nextWord = NextWord; if (nextWord.IndexOf('.') == -1) { long.TryParse(nextWord, out var result); return result; } double.TryParse(nextWord, out var result2); return result2; } private void EatWhitespace() { while (char.IsWhiteSpace(PeekChar)) { json.Read(); if (json.Peek() == -1) { break; } } } } private sealed class Serializer { private StringBuilder builder; private Serializer() { builder = new StringBuilder(); } public static string Serialize(object obj) { Serializer serializer = new Serializer(); serializer.SerializeValue(obj); return serializer.builder.ToString(); } private void SerializeValue(object value) { if (value == null) { builder.Append("null"); } else if (value is string str) { SerializeString(str); } else if (value is bool) { builder.Append(((bool)value) ? "true" : "false"); } else if (value is IList anArray) { SerializeArray(anArray); } else if (value is IDictionary obj) { SerializeObject(obj); } else if (value is char) { SerializeString(new string((char)value, 1)); } else { SerializeOther(value); } } private void SerializeObject(IDictionary obj) { bool flag = true; builder.Append('{'); foreach (object key in obj.Keys) { if (!flag) { builder.Append(','); } SerializeString(key.ToString()); builder.Append(':'); SerializeValue(obj[key]); flag = false; } builder.Append('}'); } private void SerializeArray(IList anArray) { builder.Append('['); bool flag = true; foreach (object item in anArray) { if (!flag) { builder.Append(','); } SerializeValue(item); flag = false; } builder.Append(']'); } private void SerializeString(string str) { builder.Append('"'); char[] array = str.ToCharArray(); char[] array2 = array; foreach (char c in array2) { switch (c) { case '"': builder.Append("\\\""); continue; case '\\': builder.Append("\\\\"); continue; case '\b': builder.Append("\\b"); continue; case '\f': builder.Append("\\f"); continue; case '\n': builder.Append("\\n"); continue; case '\r': builder.Append("\\r"); continue; case '\t': builder.Append("\\t"); continue; } int num = Convert.ToInt32(c); if (num >= 32 && num <= 126) { builder.Append(c); continue; } builder.Append("\\u"); builder.Append(num.ToString("x4")); } builder.Append('"'); } private void SerializeOther(object value) { if (value is float) { builder.Append(((float)value).ToString("R")); } else if (value is int || value is uint || value is long || value is sbyte || value is byte || value is short || value is ushort || value is ulong) { builder.Append(value); } else if (value is double || value is decimal) { builder.Append(Convert.ToDouble(value).ToString("R")); } else { SerializeString(value.ToString()); } } } public static object Deserialize(string json) { if (json == null) { return null; } return Parser.Parse(json); } public static string Serialize(object obj) { return Serializer.Serialize(obj); } } }