public IList <IEvent> Decode( TimingChunk timings, IEnumerable <Step> steps, IEnumerable <Trigger> triggers, IPanelMapper panelMapper) { return(_timingEventDecoder.Decode(timings) .Concat(_stepEventDecoder.Decode(steps, panelMapper)) .Concat(_triggerEventDecoder.Decode(triggers)) .OrderBy(ev => ev[NumericData.MetricOffset]) .AsList()); }
private IEnumerable <IChart> DecodeInternal(IEnumerable <Step1Chunk> data) { var chunks = data.AsList(); if (!chunks.Any()) { throw new RhythmCodexException("No chunks to decode."); } var timings = _timingChunkDecoder.Convert(chunks[0].Data); foreach (var chunk in chunks.Skip(1)) { var timingEvents = _timingEventDecoder.Decode(timings); // Decode the raw steps. var steps = _stepChunkDecoder.Convert(chunk.Data); // Old charts store singles charts twice, as if it was a couples chart. So, check for that. int?panelCount = null; var steps1 = steps.Select(s => s.Panels & 0xF).ToArray(); var steps2 = steps.Select(s => s.Panels >> 4).ToArray(); var isSingle = steps1.SequenceEqual(steps2); int?playerCount; if (isSingle) { playerCount = 1; panelCount = 4; foreach (var step in steps) { step.Panels &= 0xF; } } else { // Bit of a hack to make solo charts work. playerCount = steps.Any(s => (s.Panels & 0xA0) != 0) ? 2 : 1; panelCount = _stepPanelSplitter.Split(steps.Aggregate(0, (i, s) => i | s.Panels)).Count() / playerCount; } // Determine what kind of chart this is based on the panels used. var mapper = _panelMapperSelector.Select(steps, new ChartInfo { PanelCount = panelCount, PlayerCount = playerCount }); // Convert the steps. var stepEvents = _stepEventDecoder.Decode(steps, mapper); var events = timingEvents.Concat(stepEvents).ToList(); var info = _chartInfoDecoder.Decode(Bitter.ToInt32(chunk.Data.AsSpan(0)), mapper.PlayerCount, mapper.PanelCount); // Output metadata. var difficulty = info.Difficulty; var type = $"{SmGameTypes.Dance}-{info.Type}"; var description = $"step1 - {events.Count(ev => ev[FlagData.Note] == true)} panels - {steps.Count(s => s.Panels != 0)} steps"; var chart = new Chart { Events = events, [StringData.Difficulty] = difficulty, [StringData.Type] = type, [StringData.Description] = description }; var firstTiming = timings.Timings.OrderBy(t => t.LinearOffset).First(); chart[NumericData.LinearOffset] = chart.GetZeroLinearReference( (BigRational)firstTiming.LinearOffset / timings.Rate, (BigRational)firstTiming.MetricOffset / SsqConstants.MeasureLength); // Have a chart. :3 yield return(chart); } }