/// <summary> /// Creates a stringID resolver for a given engine version. /// </summary> /// <param name="version">The version.</param> /// <returns>The resolver.</returns> public static StringIdResolverBase Create(EngineVersion version) { if (VersionDetection.Compare(version, EngineVersion.V12_1_700123_cert_ms30_oct19) >= 0) { return(new V12_1_700123.StringIdResolver()); } if (VersionDetection.Compare(version, EngineVersion.V11_1_498295_Live) >= 0) { return(new V11_1_498295.StringIdResolver()); } return(new V1_106708.StringIdResolver()); }
/// <summary> /// Writes the map out to a CSV. /// </summary> /// <param name="writer">The writer to write to.</param> public void WriteCsv(TextWriter writer) { // Write a list of versions being represented writer.WriteLine(string.Join(",", _versionMaps.Keys.Select(VersionDetection.GetVersionString))); // Write a list of timestamps for the versions writer.WriteLine(string.Join(",", _versionMaps.Keys.Select(v => VersionDetection.GetTimestamp(v).ToString("X16")))); // Now write out each tag for (var i = 0; i < _nextGlobalTagIndex; i++) { var globalIndex = i; writer.WriteLine(string.Join(",", _versionMaps.Keys.Select(v => _versionMaps[v].GetVersionedTagIndex(globalIndex).ToString("X4")))); } }
/// <summary> /// Parses a map from a CSV. /// </summary> /// <param name="reader">The reader to read from.</param> /// <returns>The map that was read.</returns> public static TagVersionMap ParseCsv(TextReader reader) { var result = new TagVersionMap(); // Skip the first line, we don't need it if (reader.ReadLine() == null) { return(result); } // Read the timestamp list and resolve each one var timestampLine = reader.ReadLine(); if (timestampLine == null) { return(result); } var timestamps = timestampLine.Split(',').Select(t => { long r; if (long.TryParse(t, NumberStyles.HexNumber, null, out r)) { return(r); } return(-1); }); var versions = timestamps.Select(t => { EngineVersion closest; return(VersionDetection.DetectVersionFromTimestamp(t, out closest)); }).ToArray(); // Read each line and store the tag indexes in the result map while (true) { var line = reader.ReadLine(); if (line == null) { break; } if (string.IsNullOrWhiteSpace(line)) { continue; } // Parse each tag index as a hex number var tags = line.Split(','); var tagIndexes = tags.Select(t => { int r; if (int.TryParse(t, NumberStyles.HexNumber, null, out r)) { return(r); } return(-1); }).ToArray(); // Now connect all of them to the first tag for (var i = 1; i < tagIndexes.Length; i++) { if (tagIndexes[i] >= 0) { result.Add(versions[0], tagIndexes[0], versions[i], tagIndexes[i]); } } } return(result); }
static void Main(string[] args) { ConsoleHistory.Initialize(); // Get the file path from the first argument // If no argument is given, load tags.dat var filePath = (args.Length > 0) ? args[0] : "tags.dat"; // If there are extra arguments, use them to automatically execute a command List <string> autoexecCommand = null; if (args.Length > 1) { autoexecCommand = args.Skip(1).ToList(); } if (autoexecCommand == null) { Console.WriteLine("Halo Online Tag Tool [{0}]", Assembly.GetExecutingAssembly().GetName().Version); Console.WriteLine(); Console.WriteLine("Please report any bugs and feature requests at"); Console.WriteLine("<https://github.com/ElDewrito/HaloOnlineTagTool/issues>."); Console.WriteLine(); Console.Write("Reading tags..."); } // Load the tag cache FileInfo fileInfo = null; TagCache cache = null; try { fileInfo = new FileInfo(filePath); using (var stream = fileInfo.Open(FileMode.Open, FileAccess.Read)) cache = new TagCache(stream); } catch (Exception e) { Console.WriteLine("ERROR: " + e.Message); ConsoleHistory.Dump("hott_*_tags_init.log"); return; } if (autoexecCommand == null) { Console.WriteLine("{0} tags loaded.", cache.Tags.Count); } // Version detection EngineVersion closestVersion; var version = VersionDetection.DetectVersion(cache, out closestVersion); if (version != EngineVersion.Unknown) { if (autoexecCommand == null) { var buildDate = DateTime.FromFileTime(cache.Timestamp); Console.WriteLine("- Detected target engine version {0}.", VersionDetection.GetVersionString(closestVersion)); Console.WriteLine("- This cache file was built on {0} at {1}.", buildDate.ToShortDateString(), buildDate.ToShortTimeString()); } } else { Console.WriteLine("WARNING: The cache file's version was not recognized!"); Console.WriteLine("Using the closest known version {0}.", VersionDetection.GetVersionString(closestVersion)); version = closestVersion; } // Load stringIDs Console.Write("Reading stringIDs..."); var stringIdPath = Path.Combine(fileInfo.DirectoryName ?? "", "string_ids.dat"); var resolver = StringIdResolverFactory.Create(version); StringIdCache stringIds = null; try { using (var stream = File.OpenRead(stringIdPath)) stringIds = new StringIdCache(stream, resolver); } catch (IOException) { Console.WriteLine("Warning: unable to open string_ids.dat!"); Console.WriteLine("Commands which require stringID values will be unavailable."); } catch (Exception e) { Console.WriteLine("ERROR: " + e.Message); ConsoleHistory.Dump("hott_*_string_ids_init.log"); return; } if (autoexecCommand == null && stringIds != null) { Console.WriteLine("{0} strings loaded.", stringIds.Strings.Count); Console.WriteLine(); } var info = new OpenTagCache { Cache = cache, CacheFile = fileInfo, StringIds = stringIds, StringIdsFile = (stringIds != null) ? new FileInfo(stringIdPath) : null, Version = version, Serializer = new TagSerializer(version), Deserializer = new TagDeserializer(version), }; // Create command context var contextStack = new CommandContextStack(); var tagsContext = TagCacheContextFactory.Create(contextStack, info); contextStack.Push(tagsContext); // If autoexecuting a command, just run it and return if (autoexecCommand != null) { if (!ExecuteCommand(contextStack.Context, autoexecCommand)) { Console.WriteLine("Unrecognized command: {0}", autoexecCommand[0]); } return; } Console.WriteLine("Enter \"help\" to list available commands. Enter \"exit\" to quit."); while (true) { // Read and parse a command Console.WriteLine(); Console.Write("{0}> ", contextStack.GetPath()); var commandLine = Console.ReadLine(); if (commandLine == null) { break; } string redirectFile; var commandArgs = ArgumentParser.ParseCommand(commandLine, out redirectFile); if (commandArgs.Count == 0) { continue; } // If "exit" or "quit" is given, pop the current context if (commandArgs[0] == "exit" || commandArgs[0] == "quit") { if (!contextStack.Pop()) { break; // No more contexts - quit } continue; } // Handle redirection var oldOut = Console.Out; StreamWriter redirectWriter = null; if (redirectFile != null) { redirectWriter = new StreamWriter(File.Open(redirectFile, FileMode.Create, FileAccess.Write)); Console.SetOut(redirectWriter); } // Try to execute it if (!ExecuteCommand(contextStack.Context, commandArgs)) { Console.WriteLine("Unrecognized command: {0}", commandArgs[0]); Console.WriteLine("Use \"help\" to list available commands."); } // Undo redirection if (redirectFile != null) { Console.SetOut(oldOut); redirectWriter.Dispose(); Console.WriteLine("Wrote output to {0}.", redirectFile); } } }