public async Task <List <PackedEntry> > PackServerData(bool saveExecutable, ServerPresetPackMode mode, bool evbMode, CancellationToken cancellation) { var result = new List <PackedEntry>(); // Wrapper if (ProvideDetails && DetailsMode == ServerPresetDetailsMode.ViaWrapper) { if (saveExecutable) { string wrapper; switch (mode) { case ServerPresetPackMode.Linux32: wrapper = await LoadLinux32Wrapper(cancellation); break; case ServerPresetPackMode.Linux64: wrapper = await LoadLinux64Wrapper(cancellation); break; case ServerPresetPackMode.Windows: wrapper = await LoadWinWrapper(cancellation); break; default: throw new ArgumentOutOfRangeException(nameof(mode), mode, null); } if (cancellation.IsCancellationRequested) { return(null); } if (wrapper == null) { throw new InformativeException("Can’t pack server", "Can’t load server wrapper."); } // Actual wrapper, compiled to a single exe-file result.Add(PackedEntry.FromFile( mode == ServerPresetPackMode.Windows ? @"acServerWrapper.exe" : @"acServerWrapper", wrapper)); // For EVB if (evbMode) { result.Add(PackedEntry.FromContent("arguments.json", new JArray { @"--copy-executable-to=acServer_tmp.exe", }.ToString(Formatting.Indented))); } } // Params var wrapperParams = _wrapperParamsJson?.DeepClone() as JObject; SetWrapperParams(ref wrapperParams); result.Add(PackedEntry.FromContent(@"cfg/cm_wrapper_params.json", wrapperParams.ToString(Formatting.Indented))); // Content if (DetailsContentJObject != null) { void ProcessPiece(JObject piece) { var file = (string)piece?[@"file"]; if (piece == null || file == null) { return; } var filename = Path.IsPathRooted(file) ? file : Path.Combine(WrapperContentDirectory, file); if (!FileUtils.ArePathsEqual(WrapperContentDirectory, Path.GetDirectoryName(filename))) { piece[@"file"] = Path.GetFileName(filename); } result.Add(PackedEntry.FromFile($"cfg/cm_content/{Path.GetFileName(filename)}", filename)); } void ProcessPieces(JToken token, string childrenKey = null) { if (!(token is JObject o)) { return; } foreach (var t in o) { var b = (JObject)t.Value; if (b == null) { continue; } ProcessPiece(b); if (childrenKey != null) { ProcessPieces(b[childrenKey]); } } } var content = DetailsContentJObject.DeepClone(); ProcessPieces(content[@"cars"], @"skins"); ProcessPiece(content[@"track"] as JObject); ProcessPieces(content[@"weather"]); result.Add(PackedEntry.FromContent("cfg/cm_content/content.json", content.ToString(Formatting.Indented))); } else { result.Add(PackedEntry.FromContent("cfg/cm_content/content.json", @"{}")); } } // Executable if (saveExecutable) { var serverDirectory = ServerPresetsManager.ServerDirectory; result.Add(PackedEntry.FromFile( mode == ServerPresetPackMode.Windows ? @"acServer.exe" : @"acServer", Path.Combine(serverDirectory, mode == ServerPresetPackMode.Windows ? @"acServer.exe" : @"acServer"))); } // Main config file var serverCfg = IniObject?.Clone() ?? new IniFile(IniFileMode.ValuesWithSemicolons); var dataSection = serverCfg["DATA"]; SaveData(serverCfg); if (ProvideDetails) { if (DetailsMode == ServerPresetDetailsMode.ViaWrapper) { serverCfg["SERVER"].Set("NAME", $"{Name} {ServerEntry.ExtendedSeparator}{WrapperPort}"); } else { await EnsureDetailsNameIsActualAsync(serverCfg); } } // Welcome message if (!string.IsNullOrEmpty(WelcomeMessage)) { result.Add(PackedEntry.FromContent("cfg/welcome.txt", WelcomeMessage)); serverCfg["SERVER"].Set("WELCOME_MESSAGE", "cfg/welcome.txt"); dataSection.Set("WELCOME_PATH", "cfg/welcome.txt"); } // Setups var setupIndex = 0; foreach (var key in dataSection.Keys.Where(x => x.StartsWith(@"FIXED_SETUP_")).ToList()) { dataSection.Remove(key); } foreach (var item in SetupItems) { if (!File.Exists(item.Filename)) { continue; } var name = $@"cfg/setup_{setupIndex}_{item.CarId}.ini"; result.Add(PackedEntry.FromFile(name, item.Filename)); dataSection[@"FIXED_SETUP_" + setupIndex] = $@"{(item.IsDefault ? @"1" : @"0")}|{name}"; setupIndex++; } result.Add(PackedEntry.FromContent("cfg/server_cfg.ini", serverCfg.Stringify())); // Entry list var entryList = EntryListIniObject?.Clone() ?? new IniFile(); entryList.SetSections("CAR", DriverEntries, (entry, section) => entry.SaveTo(section)); result.Add(PackedEntry.FromContent("cfg/entry_list.ini", entryList.Stringify())); // Cars var root = AcRootDirectory.Instance.RequireValue; for (var i = 0; i < CarIds.Length; i++) { var carId = CarIds[i]; var packedData = Path.Combine(AcPaths.GetCarDirectory(root, carId), "data.acd"); if (File.Exists(packedData)) { result.Add(PackedEntry.FromFile(Path.Combine(@"content", @"cars", carId, @"data.acd"), packedData)); } } // Track var localPath = TrackLayoutId != null?Path.Combine(TrackId, TrackLayoutId) : TrackId; foreach (var file in TrackDataToKeep) { var actualData = Path.Combine(AcPaths.GetTracksDirectory(root), localPath, @"data", file); if (File.Exists(actualData)) { result.Add(PackedEntry.FromFile(Path.Combine(@"content", @"tracks", localPath, @"data", file), actualData)); } } // System var systemSurfaces = Path.Combine(ServerPresetsManager.ServerDirectory, "system", "data", "surfaces.ini"); if (File.Exists(systemSurfaces)) { result.Add(PackedEntry.FromFile("system/data/surfaces.ini", systemSurfaces)); } return(result); }