void GenTiming(ArcaeaFileFormatParser.EventContext context) { RejectSubevents(context, "timing"); RejectSegment(context, "timing"); if (!CheckValuesCount(context, "timing", 3)) { return; } var timing = CheckValueType <RawAffInt>(context.values().value()[0], "hold", "时间"); var bpm = CheckValueType <RawAffFloat>(context.values().value()[1], "hold", "BPM"); var segment = CheckValueType <RawAffFloat>(context.values().value()[2], "hold", "单个小节拍数"); if (timing == null || bpm == null || segment == null) { return; } bool valueError = false; if (segment.data < 0) { chart.warning.Add($"第 {context.values().value()[2].Start.Line + lineOffset} 行第 {context.values().value()[2].Start.Column + 1} 列,timing 事件的单个小节拍数小于 0,此 timing 将被忽略"); valueError = true; } if (!valueError) { context.value = new RawAffTiming() { Timing = timing.data, Bpm = bpm.data, BeatsPerLine = segment.data }; } }
void RejectSegment(ArcaeaFileFormatParser.EventContext context, string type) { if (context.segment() != null) { chart.warning.Add($"第 {context.subevents().Start.Line + lineOffset} 行第 {context.subevents().Start.Column + 1} 列,{type} 事件不应包含事件块,此事件块将被忽略"); } }
void GenSceneControl(ArcaeaFileFormatParser.EventContext context) { RejectSubevents(context, "scenecontrol"); RejectSegment(context, "scenecontrol"); if (!EnsureValuesCount(context, "scenecontrol", 2)) { return; } var timing = CheckValueType <RawAffInt>(context.values().value()[0], "scenecontrol", "时间"); var type = CheckValueType <RawAffWord>(context.values().value()[1], "scenecontrol", "类型"); if (timing == null || type == null) { return; } List <IRawAffValue> @params = new List <IRawAffValue>(); foreach (var value in context.values().value().Skip(2)) { if (value.value == null) { return; } @params.Add(value.value); } context.value = new RawAffSceneControl() { Timing = timing.data, Type = type.data, Params = @params, }; }
void GenTap(ArcaeaFileFormatParser.EventContext context) { RejectSubevents(context, "tap"); RejectSegment(context, "tap"); if (!CheckValuesCount(context, "tap", 2)) { return; } var timing = CheckValueType <RawAffInt>(context.values().value()[0], "tap", "时间"); var track = CheckValueType <RawAffInt>(context.values().value()[1], "tap", "轨道"); if (timing == null || track == null) { return; } bool valueError = false; if (track.data > 4 || track.data <= 0) { chart.warning.Add($"第 {context.values().value()[1].Start.Line + lineOffset} 行第 {context.values().value()[1].Start.Column + 1} 列,tap 事件的轨道参数超过范围,此 tap 将被忽略"); valueError = true; } if (!valueError) { context.value = new RawAffTap() { Timing = timing.data, Track = track.data }; } }
bool LimitValuesCount(ArcaeaFileFormatParser.EventContext context, string type, int count) { if (context.values().value().Length > count) { chart.warning.Add($"第 {context.values().Start.Line + lineOffset} 行第 {context.values().Start.Column + 1} 列,{type} 事件的参数个数应当为至多 {count} 个而非 {context.values().value().Length} 个,此事件将被忽略"); return(false); } return(true); }
void GenCamera(ArcaeaFileFormatParser.EventContext context) { RejectSubevents(context, "camera"); RejectSegment(context, "camera"); if (!CheckValuesCount(context, "camera", 9)) { return; } var timing = CheckValueType <RawAffInt>(context.values().value()[0], "camera", "时间"); var moveX = CheckValueType <RawAffFloat>(context.values().value()[1], "camera", "平移 X 轴"); var moveY = CheckValueType <RawAffFloat>(context.values().value()[2], "camera", "平移 Y 轴"); var moveZ = CheckValueType <RawAffFloat>(context.values().value()[3], "camera", "平移 Z 轴"); var rotateX = CheckValueType <RawAffFloat>(context.values().value()[4], "camera", "旋转 X 轴"); var rotateY = CheckValueType <RawAffFloat>(context.values().value()[5], "camera", "旋转 Y 轴"); var rotateZ = CheckValueType <RawAffFloat>(context.values().value()[6], "camera", "旋转 Z 轴"); var rawCameraType = CheckValueType <RawAffWord>(context.values().value()[7], "camera", "camera 类型"); var cameraType = ParseWord <CameraEaseType>(cameraTypes, rawCameraType.data, context.values().value()[7], "camera", "camera 类型"); var duration = CheckValueType <RawAffInt>(context.values().value()[8], "camera", "时长"); if (timing == null || moveX == null || moveY == null || moveZ == null || rotateX == null || rotateY == null || rotateZ == null || cameraType == null || duration == null) { return; } bool valueError = false; if (duration.data < 0) { chart.warning.Add($"第 {context.values().value()[8].Start.Line + lineOffset} 行第 {context.values().value()[8].Start.Column + 1} 列,camera 事件的时长小于零,作为修复其时长见会被设为零"); duration.data = 0; } if (!valueError) { context.value = new RawAffCamera() { Timing = timing.data, MoveX = moveX.data, MoveY = moveY.data, MoveZ = moveZ.data, RotateX = rotateX.data, RotateY = rotateY.data, RotateZ = rotateZ.data, CameraType = cameraType.Value, Duration = duration.data, }; } }
void GenArctap(ArcaeaFileFormatParser.EventContext context) { RejectSubevents(context, "arctap"); RejectSegment(context, "arctap"); if (!CheckValuesCount(context, "arctap", 1)) { return; } var timing = CheckValueType <RawAffInt>(context.values().value()[0], "arctap", "时间"); if (timing == null) { return; } context.value = new RawAffArctap() { Timing = timing.data }; }
public override void ExitEvent(ArcaeaFileFormatParser.EventContext context) { if (context.Word() == null) { GenTap(context); } else { string tag = context.Word().GetText(); if (tag == "hold") { GenHold(context); } else if (tag == "timing") { GenTiming(context); } else if (tag == "arc") { GenArc(context); } else if (tag == "arctap") { GenArctap(context); } else if (tag == "camera") { GenCamera(context); } else if (tag == "scenecontrol") { GenSceneControl(context); } else if (tag == "timinggroup") { GenTimingGroup(context); } else { chart.warning.Add($"第 {context.Start.Line + lineOffset} 行第 {context.Start.Column + 1} 列,不支持的事件类型:{context.Word().GetText()},该事件将被忽略"); } } }
void GenTimingGroup(ArcaeaFileFormatParser.EventContext context) { RejectSubevents(context, "timinggroup"); LimitValuesCount(context, "timinggroup", 1); List <IRawAffNestableItem> items = new List <IRawAffNestableItem>(); TimingGroupType? timingGroupType = TimingGroupType.Normal; if (context.values().value().Length > 0) { var rawTimingGroupType = CheckValueType <RawAffWord>(context.values().value()[0], "arc", "arc 类型"); timingGroupType = ParseWord(timingGroupTypes, rawTimingGroupType.data, context.values().value()[0], "arc", "arc 类型"); } foreach (var item in context.segment().body().item()) { IRawAffEvent @event = item.@event().value; if (!(@event is IRawAffItem)) { chart.warning.Add($"第 {item.@event().Start.Line + lineOffset} 行第 {item.@event().Start.Column + 1} 列,不可作为物件使用的事件:{item.@event().GetText()},此事件将被忽略"); continue; } IRawAffItem rawItem = @event as IRawAffItem; if (!(rawItem is IRawAffNestableItem)) { chart.warning.Add($"第 {item.Start.Line + lineOffset} 行第 {item.Start.Column + 1} 列,不可在 timinggroup 中嵌套使用的物件:{item.@event().GetText()},此物件将被忽略"); nonNestableItems.Add(rawItem); continue; } items.Add(rawItem as IRawAffNestableItem); } if (timingGroupType == null) { return; } context.value = new RawAffTimingGroup() { Items = items, Type = timingGroupType.Value, }; }
void GenHold(ArcaeaFileFormatParser.EventContext context) { RejectSubevents(context, "hold"); RejectSegment(context, "hold"); if (!CheckValuesCount(context, "hold", 3)) { return; } var timing = CheckValueType <RawAffInt>(context.values().value()[0], "hold", "时间"); var endTiming = CheckValueType <RawAffInt>(context.values().value()[1], "hold", "结束时间"); var track = CheckValueType <RawAffInt>(context.values().value()[2], "hold", "轨道"); if (timing == null || endTiming == null || track == null) { return; } bool valueError = false; if (endTiming.data < timing.data) { chart.warning.Add($"第 {context.values().value()[1].Start.Line + lineOffset} 行第 {context.values().value()[1].Start.Column + 1} 列,hold 事件的结束时间早于开始时间,作为修复将会交换起止时间"); var tmp = timing; timing = endTiming; endTiming = tmp; } if (track.data > 4 || track.data <= 0) { chart.warning.Add($"第 {context.values().value()[2].Start.Line + lineOffset} 行第 {context.values().value()[2].Start.Column + 1} 列,hold 事件的轨道参数超过范围,此 hold 将被忽略"); valueError = true; } if (!valueError) { context.value = new RawAffHold() { Timing = timing.data, EndTiming = endTiming.data, Track = track.data }; } }
void GenArc(ArcaeaFileFormatParser.EventContext context) { RejectSegment(context, "arc"); if (!CheckValuesCount(context, "arc", 10)) { return; } var timing = CheckValueType <RawAffInt>(context.values().value()[0], "arc", "时间"); var endTiming = CheckValueType <RawAffInt>(context.values().value()[1], "arc", "结束时间"); var xStart = CheckValueType <RawAffFloat>(context.values().value()[2], "arc", "起点横坐标"); var xEnd = CheckValueType <RawAffFloat>(context.values().value()[3], "arc", "终点横坐标"); var rawLineType = CheckValueType <RawAffWord>(context.values().value()[4], "arc", "arc 类型"); var lineType = ParseWord(lineTypes, rawLineType.data, context.values().value()[4], "arc", "arc 类型"); var yStart = CheckValueType <RawAffFloat>(context.values().value()[5], "arc", "起点纵坐标"); var yEnd = CheckValueType <RawAffFloat>(context.values().value()[6], "arc", "终点纵坐标"); var color = CheckValueType <RawAffInt>(context.values().value()[7], "arc", "颜色"); var effect = CheckValueType <RawAffWord>(context.values().value()[8], "arc", "效果类型"); var rawIsVoid = CheckValueType <RawAffWord>(context.values().value()[9], "arc", "是否黑线"); var isVoid = ParseWord(bools, rawIsVoid.data, context.values().value()[9], "arc", "是否黑线"); if (timing == null || endTiming == null || xStart == null || xEnd == null || lineType == null || yStart == null || yEnd == null || color == null || effect == null || isVoid == null) { return; } bool valueError = false; if (endTiming.data < timing.data) { chart.warning.Add($"第 {context.values().value()[1].Start.Line + lineOffset} 行第 {context.values().value()[1].Start.Column + 1} 列,arc 事件的结束时间早于开始时间,作为修复将会交换起止时间"); var tmp = timing; timing = endTiming; endTiming = tmp; } if (color.data < 0 || color.data >= 3) { chart.warning.Add($"第 {context.values().value()[7].Start.Line + lineOffset} 行第 {context.values().value()[7].Start.Column + 1} 列,arc 事件的颜色超出范围,作为修复其颜色见会被设为红色"); color.data = 0; } List <RawAffArctap> arctaps = new List <RawAffArctap>(); var subevents = context.subevents(); if (subevents != null) { foreach (var @event in context.subevents().@event()) { if (@event.value != null) { if (@event.value is RawAffArctap) { var arctap = @event.value as RawAffArctap; if (arctap.Timing < timing.data || arctap.Timing > endTiming.data) { chart.warning.Add($"第 {@event.values().value()[0].Start.Line + lineOffset} 行第 {@event.values().value()[0].Start.Column + 1} 列,arctap 事件的时间超出所属 arc 的时间范围,此 arctap 事件将被忽略"); } else { arctaps.Add(arctap); } } else { chart.warning.Add($"第 {@event.Start.Line + lineOffset} 行第 {@event.Start.Column + 1} 列,arc 事件的子事件必须为 arctap 事件,此事件将被忽略"); } } } } if (!valueError) { context.value = new RawAffArc() { Timing = timing.data, EndTiming = endTiming.data, XStart = xStart.data, XEnd = xEnd.data, LineType = lineType.Value, YStart = yStart.data, YEnd = yEnd.data, Color = color.data, IsVoid = isVoid.Value, ArcTaps = arctaps, }; } }
/// <summary> /// Exit a parse tree produced by <see cref="ArcaeaFileFormatParser.event"/>. /// <para>The default implementation does nothing.</para> /// </summary> /// <param name="context">The parse tree.</param> public virtual void ExitEvent([NotNull] ArcaeaFileFormatParser.EventContext context) { }