public async Task Cloud([Remainder] string arguments = null) { var args = CommandHelper.ParseArgs(arguments, new { ClusterKey = "", Backup = 0L, Stash = 0L, Pop = 0L, Delete = 0L, List = 0L, Details = 0L, Restore = 0L, Target1 = "", Target2 = "", Skip = 0 }, x => x.For(y => y.ClusterKey, noPrefix: true) .For(y => y.Target1, noPrefix: true) .For(y => y.Target2, noPrefix: true)); var sb = new StringBuilder(); var r_allowedExt = new Regex(@"^(?!tmpprofile)([a-z0-9])+$", RegexOptions.Singleline | RegexOptions.IgnoreCase); //for details and restore commands, get hashes from target1 and target2 int?backupHash = null, cloudSaveHash = null; if (args.Details > 0 || args.Restore > 0) { try { backupHash = !string.IsNullOrWhiteSpace(args.Target1) ? (int?)Convert.ToInt32(args.Target1, 16) : null; } catch { /*ignore exceptions*/ } } if (args.Restore > 0) { try { cloudSaveHash = !string.IsNullOrWhiteSpace(args.Target2) ? (int?)Convert.ToInt32(args.Target2, 16) : null; } catch { /*ignore exceptions*/ } } // for stash and pop commands, check that target1 is a valid tag if ((args.Stash > 0 || args.Pop > 0) && !r_allowedExt.IsMatch(args.Target1)) { await Context.Channel.SendMessageAsync($"**The supplied tag is not allowed (only a-z, 0-9)!**"); return; } // check that the cluster key is valid ArkClusterContext clusterContext = args.ClusterKey != null?_contextManager.GetCluster(args.ClusterKey) : null; if (clusterContext == null) { await Context.Channel.SendMessageAsync($"**Cloud commands need to be prefixed with a valid cluster key.**"); return; } // check that there are one or more servers in the cluster var serverContexts = _contextManager.GetServersInCluster(clusterContext.Config.Key); if (!(serverContexts?.Length > 0)) { await Context.Channel.SendMessageAsync($"**There are no servers in the cluster.**"); return; } /* --------------------------------------------------------------- * List cloud save backups available for a given player. * --------------------------------------------------------------- */ if (args.List > 0) { var result = GetBackupFiles(clusterContext.Config, serverContexts.Select(x => x.Config.Key).ToArray(), args.List); if (result.Count > 0) { var tbl = OutputCloudBackupListingTable(result, args.Skip); sb.Append(tbl); } else { sb.AppendLine("**Could not find any cloud save backups...**"); } } /* --------------------------------------------------------------- * Stash the current cloud save with a given tag to fetch at a later time. * --------------------------------------------------------------- */ else if (args.Stash > 0) { var result = _savegameBackupService.StashCloudSave(clusterContext.Config, args.Stash, args.Target1); if (result == StashResult.Successfull) { sb.AppendLine($"**Cloud save stashed as '{args.Target1}'!**"); } else if (result == StashResult.SourceMissing) { sb.AppendLine("**There is no cloud save to stash...**"); } else if (result == StashResult.TargetExists) { sb.AppendLine("**The supplied tag is already being used...**"); } else { sb.AppendLine("**Failed to stash cloud save...**"); } } /* --------------------------------------------------------------- * Fetch a cloud save previously stashed with a given tag and set it as the current cloud save. * --------------------------------------------------------------- */ else if (args.Pop > 0) { var result = _savegameBackupService.PopCloudSave(clusterContext.Config, args.Pop, args.Target1); if (result == StashResult.Successfull) { sb.AppendLine($"**Cloud save popped from '{args.Target1}'!**"); } else if (result == StashResult.SourceMissing) { sb.AppendLine("**The supplied tag does not exist...**"); } else if (result == StashResult.TargetExists) { sb.AppendLine("**A cloud save already exists, please delete/stash it before popping...**"); } else { sb.AppendLine("**Failed to pop cloud save...**"); } } /* --------------------------------------------------------------- * Delete the current cloud save for a given player. * --------------------------------------------------------------- */ else if (args.Delete > 0) { var targetPath = Path.Combine(clusterContext.Config.SavePath, $"{args.Delete}"); if (File.Exists(targetPath)) { try { File.Delete(targetPath); sb.AppendLine($"**Cloud save deleted!**"); } catch { sb.AppendLine($"**Failed to delete cloud save...**"); } } else { sb.AppendLine($"**There is no cloud save to delete...**"); } } /* --------------------------------------------------------------- * Create a backup of all cloud save files for a given player (including stashed, .tmpprofile etc.) * --------------------------------------------------------------- */ else if (args.Backup > 0) { var result = _savegameBackupService.CreateClusterBackupForSteamId(clusterContext.Config, args.Backup); if (result != null && result.ArchivePaths?.Length > 0) { sb.AppendLine($"**Cloud save backup successfull!**"); } else { sb.AppendLine("**Failed to backup cloud save...**"); } } /* --------------------------------------------------------------- * Get detailed information for a single backup archive or cloud save file. * --------------------------------------------------------------- */ else if (args.Details > 0 && backupHash.HasValue) { var result = GetBackupFiles(clusterContext.Config, serverContexts.Select(x => x.Config.Key).ToArray(), args.Details, backupHash.Value) .Find(x => x.Path.GetHashCode() == backupHash.Value); if (result == null) { await Context.Channel.SendMessageAsync($"**Failed to find the given backup hash!**"); return; } var data = result.Files.Select(file => { string tmpFilePath = null; ArkCloudInventory cloudInventory = null; try { string filePath = null; if (result is FromServerBackupListEntity) { filePath = result.FullPath; } else { filePath = tmpFilePath = FileHelper.ExtractFileInZipFile(result.FullPath, file); } var cresult = ArkClusterData.LoadSingle(filePath, CancellationToken.None, true, true); cloudInventory = cresult.Success ? cresult.Data : null; } catch { /*ignore exception*/ } finally { if (tmpFilePath != null) { File.Delete(tmpFilePath); } } return(new { FilePath = file, CloudSaveHash = file.GetHashCode(), DinoCount = cloudInventory?.Dinos?.Length, CharactersCount = cloudInventory?.Characters?.Length, ItemsCount = cloudInventory?.Items?.Length }); }).ToArray(); var tableBackupFiles = FixedWidthTableHelper.ToString(data, x => x .For(y => y.FilePath, header: "Cloud Save") .For(y => y.CloudSaveHash, header: "Cloud Save Hash", alignment: 1, format: "X") .For(y => y.DinoCount, header: "Dinos", alignment: 1) .For(y => y.CharactersCount, header: "Characters", alignment: 1) .For(y => y.ItemsCount, header: "Items", alignment: 1)); var tableBackupEntries = OutputCloudBackupListingTable(new[] { result }, 0, 1); sb.Append(tableBackupEntries); sb.Append($"```{tableBackupFiles}```"); } /* --------------------------------------------------------------- * Restore a single cloud save file from a backup archive or cloud save file (some overlap with the less verbose pop command). * --------------------------------------------------------------- */ else if (args.Restore > 0 && backupHash.HasValue && cloudSaveHash.HasValue) { var result = GetBackupFiles(clusterContext.Config, serverContexts.Select(x => x.Config.Key).ToArray(), args.Restore, backupHash.Value) .Find(x => x.Path.GetHashCode() == backupHash.Value); if (result == null) { await Context.Channel.SendMessageAsync($"**Failed to find the given backup hash!**"); return; } var cloudSaveFile = result.Files.FirstOrDefault(x => x.GetHashCode() == cloudSaveHash.Value); if (cloudSaveFile == null) { await Context.Channel.SendMessageAsync($"**Failed to find the given cloud save hash!**"); return; } var targetPath = Path.Combine(clusterContext.Config.SavePath, $"{args.Restore}"); if (File.Exists(targetPath)) { await Context.Channel.SendMessageAsync("**A cloud save already exists, please delete/stash it before restoring...**"); return; } string tmpFilePath = null; try { string filePath = null; if (result is FromServerBackupListEntity) { filePath = result.FullPath; } else { filePath = tmpFilePath = FileHelper.ExtractFileInZipFile(result.FullPath, cloudSaveFile); } File.Copy(filePath, targetPath); sb.AppendLine($"**Cloud save successfully restored!**"); } catch { /*ignore exception*/ sb.AppendLine($"**Failed to restore cloud save...**"); } finally { if (tmpFilePath != null) { File.Delete(tmpFilePath); } } } else { var syntaxHelp = MethodBase.GetCurrentMethod().GetCustomAttribute <SyntaxHelpAttribute>()?.SyntaxHelp; var name = MethodBase.GetCurrentMethod().GetCustomAttribute <CommandAttribute>()?.Text; await Context.Channel.SendMessageAsync(string.Join(Environment.NewLine, new string[] { $"**My logic circuits cannot process this command! I am just a bot after all... :(**", !string.IsNullOrWhiteSpace(syntaxHelp) ? $"Help me by following this syntax: **!{name}** {syntaxHelp}" : null }.Where(x => x != null))); return; } var msg = sb.ToString(); if (!string.IsNullOrWhiteSpace(msg)) { await CommandHelper.SendPartitioned(Context.Channel, sb.ToString()); } }
internal static PlayerClusterViewModel BuildClusterViewModelForPlayer(ArkClusterContext context, ArkCloudInventory cloudInventory, DemoMode demoMode, bool incCreaturesCloud) { var vm = new PlayerClusterViewModel(); if (incCreaturesCloud) { foreach (var c in cloudInventory.Dinos) { var aliases = ArkSpeciesAliases.Instance.GetAliasesByClassName(c.ClassName); var vmc = new CloudCreatureViewModel { Name = demoMode?.GetCreatureName(c.Id1, c.Id2, aliases?.FirstOrDefault()) ?? c.Name, ClassName = c.ClassName, Species = aliases?.FirstOrDefault(), Aliases = aliases?.Skip(2).ToArray() ?? new string[] { }, //skip primary name and class name Level = c.Level }; vm.Creatures.Add(vmc); } } return(vm); }
protected override void RunCommand(IEnumerable <string> args) { List <string> argsList = args.ToList(); if (showCommandHelp(argsList)) { return; } string clusterDirectory = argsList[0]; string outputDirectory = argsList[1]; ArkDataManager.LoadData(GlobalOptions.Language); List <Action> tasks = GlobalOptions.Parallel ? new List <Action>() : null; Stopwatch stopwatch = new Stopwatch(GlobalOptions.UseStopWatch); foreach (string path in Directory.EnumerateFiles(clusterDirectory)) { Action task = () => { try { ArkCloudInventory cloudInventory = new ArkCloudInventory().ReadBinary <ArkCloudInventory>(path, ReadingOptions.Create()); CustomDataContext context = new CustomDataContext { ObjectContainer = cloudInventory }; IPropertyContainer arkData = cloudInventory.InventoryData.GetPropertyValue <IPropertyContainer>("MyArkData"); CommonFunctions.WriteJson(Path.Combine(outputDirectory, path + ".json"), (generator, writingOptions) => { generator.WriteStartObject(); ArkArrayStruct tamedDinosData = arkData.GetPropertyValue <ArkArrayStruct>("ArkTamedDinosData"); if (tamedDinosData != null && tamedDinosData.Any()) { generator.WriteArrayFieldStart("creatures"); foreach (IStruct dinoStruct in tamedDinosData) { IPropertyContainer dino = (IPropertyContainer)dinoStruct; ArkContainer container = null; if (cloudInventory.InventoryVersion == 1) { ArkArrayUInt8 byteData = dino.GetPropertyValue <ArkArrayUInt8>("DinoData"); container = new ArkContainer(byteData); } else if (cloudInventory.InventoryVersion == 3) { ArkArrayInt8 byteData = dino.GetPropertyValue <ArkArrayInt8>("DinoData"); container = new ArkContainer(byteData); } ObjectReference dinoClass = dino.GetPropertyValue <ObjectReference>("DinoClass"); // Skip "BlueprintGeneratedClass " = 24 chars string dinoClassName = dinoClass.ObjectString.ToString().Substring(24); generator.WriteStartObject(); generator.WriteField("type", ArkDataManager.HasCreatureByPath(dinoClassName) ? ArkDataManager.GetCreatureByPath(dinoClassName).Name : dinoClassName); // NPE for unknown versions Creature creature = new Creature(container.Objects[0], container); generator.WriteObjectFieldStart("data"); creature.writeAllProperties(generator, context, writeAllFields); generator.WriteEndObject(); generator.WriteEndObject(); } generator.WriteEndArray(); } ArkArrayStruct arkItems = arkData.GetPropertyValue <ArkArrayStruct>("ArkItems"); if (arkItems != null) { List <Item> items = new List <Item>(); foreach (IStruct itemStruct in arkItems) { IPropertyContainer item = (IPropertyContainer)itemStruct; IPropertyContainer netItem = item.GetPropertyValue <IPropertyContainer>("ArkTributeItem"); items.Add(new Item(netItem)); } if (items.Any()) { generator.WritePropertyName("items"); Inventory.writeInventoryLong(generator, context, items, writeAllFields); } } generator.WriteEndObject(); }, writingOptions); } catch (Exception ex) { Console.Error.WriteLine("Found potentially corrupt cluster data: " + path); if (GlobalOptions.Verbose) { Console.Error.WriteLine(ex.Message); Console.Error.WriteLine(ex.StackTrace); } } }; if (tasks != null) { tasks.Add(task); } else { task(); } } if (tasks != null) { Parallel.ForEach(tasks, task => task()); } stopwatch.Stop("Loading cluster data and writing info"); stopwatch.Print(); }