using System; using System.Collections.Generic; using System.Globalization; using System.Numerics; using System.Text.RegularExpressions; namespace AcDream.Core.Tests.Conformance; /// /// A single retail find_cell_list pick captured via cdb (golden oracle). /// is the seed/current cell at find_cell_list /// entry; is the chosen containing cell /// (retail *arg5 in CObjCell::find_cell_list @ 0x52b4e0 pc:308742). /// public sealed record RetailCellPick(uint SeedCellId, Vector3 Position, uint PickedCellId); /// Parser for the find-cell-list-capture.cdb log format. public static class RetailTrace { private static readonly Regex Fcl = new( @"^\[fcl\]\s+seed=0x(?[0-9A-Fa-f]{1,8})\s+" + @"px=(?-?\d+(\.\d+)?)\s+py=(?-?\d+(\.\d+)?)\s+pz=(?-?\d+(\.\d+)?)\s+" + @"picked=0x(?[0-9A-Fa-f]{1,8})\s*$", RegexOptions.Compiled); public static RetailCellPick? ParseFindCellList(string line) { if (string.IsNullOrEmpty(line)) return null; var m = Fcl.Match(line); if (!m.Success) return null; var ci = CultureInfo.InvariantCulture; return new RetailCellPick( SeedCellId: Convert.ToUInt32(m.Groups["seed"].Value, 16), Position: new Vector3( float.Parse(m.Groups["px"].Value, ci), float.Parse(m.Groups["py"].Value, ci), float.Parse(m.Groups["pz"].Value, ci)), PickedCellId: Convert.ToUInt32(m.Groups["picked"].Value, 16)); } /// Parse a log, skipping every non-matching line (noise/banner/other BPs). public static IReadOnlyList ParseAll(IEnumerable lines) { var list = new List(); foreach (var line in lines) { var rec = ParseFindCellList(line); if (rec is not null) list.Add(rec); } return list; } }