public void SaveToDraftTimeline( string file, IList <CombatLog> combatLogs) { if (!combatLogs.Any()) { return; } var outputTypes = new[] { LogTypes.CastStart, LogTypes.Action, LogTypes.Dialog, LogTypes.Added, LogTypes.Marker, LogTypes.Effect, LogTypes.NetworkAbility, LogTypes.NetworkAOEAbility, }; var timeline = new TimelineModel(); timeline.Zone = combatLogs.First().Zone; timeline.Locale = Settings.Default.FFXIVLocale; timeline.TimelineName = $"{timeline.Zone} draft timeline"; timeline.Revision = "draft"; timeline.Description = "自動生成によるドラフト版タイムラインです。タイムライン定義の作成にご活用ください。" + Environment.NewLine + "なお未編集のままで運用できるようには設計されていません。"; foreach (var log in combatLogs.Where(x => outputTypes.Contains(x.LogType))) { var a = new TimelineActivityModel() { Time = log.TimeStampElapted, Text = log.Text, SyncKeyword = log.SyncKeyword, }; switch (log.LogType) { case LogTypes.CastStart: a.Notice = $"次は、{log.Skill}。"; break; case LogTypes.Action: // 構えのないアクションか? if (!combatLogs.Any(x => x.ID < log.ID && x.Skill == log.Skill && x.LogType == LogTypes.CastStart && (log.TimeStamp - x.TimeStamp).TotalSeconds <= 12)) { a.Notice = $"次は、{log.Skill}。"; } else { continue; } break; case LogTypes.Added: a.Notice = $"次は、{log.Actor}。"; if (timeline.Activities.Any(x => x.Time == a.Time && x.Text == a.Text && x.SyncKeyword == a.SyncKeyword)) { continue; } break; case LogTypes.Marker: case LogTypes.Effect: a.Enabled = false; if (timeline.Activities.Any(x => x.Time == a.Time && x.Text == a.Text)) { continue; } break; case LogTypes.NetworkAbility: case LogTypes.NetworkAOEAbility: a.Enabled = false; if (timeline.Activities.Any(x => x.Time == a.Time && x.Text == a.Text)) { continue; } break; } timeline.Add(a); } timeline.Save(file); }
private void NotifyActivity( TimelineActivityModel act) { if (string.IsNullOrEmpty(act.Name) && string.IsNullOrEmpty(act.Text) && string.IsNullOrEmpty(act.Notice)) { act.IsNotified = true; return; } var now = DateTime.Now; var offset = this.CurrentTime - act.Time; var log = $"{TLSymbol} Notice from TL. " + $"name={act.Name}, text={act.TextReplaced}, notice={act.NoticeReplaced}, offset={offset.TotalSeconds:N1}"; var notice = act.NoticeReplaced ?? string.Empty; notice = TimelineExpressionsModel.ReplaceText(notice); if (string.Equals(notice, "auto", StringComparison.OrdinalIgnoreCase)) { notice = !string.IsNullOrEmpty(act.TextReplaced) ? act.TextReplaced : act.Name; if (offset.TotalSeconds <= -1.0) { var offsetText = (offset.TotalSeconds * -1).ToString("N0"); notice += $" まで、あと{offsetText}秒"; } if (!string.IsNullOrEmpty(notice)) { notice += "。"; } } var isSync = (TimelineRazorModel.Instance?.SyncTTS ?? false) || act.NoticeSync.Value; RaiseLog(log); NotifySoundAsync(notice, act.NoticeDevice.GetValueOrDefault(), isSync, act.NoticeVolume); var vnotices = act.VisualNoticeStatements .Where(x => x.Enabled.GetValueOrDefault()) .Select(x => x.Clone()); var inotices = act.ImageNoticeStatements .Where(x => x.Enabled.GetValueOrDefault()); if (!vnotices.Any() && !inotices.Any()) { return; } var placeholders = TimelineManager.Instance.GetPlaceholders(); foreach (var v in vnotices) { // ソート用にログ番号を格納する // 優先順位は最後尾とする v.LogSeq = long.MaxValue; v.Timestamp = DateTime.Now; switch (v.Text) { case TimelineVisualNoticeModel.ParentTextPlaceholder: v.TextToDisplay = act.TextReplaced; break; case TimelineVisualNoticeModel.ParentNoticePlaceholder: v.TextToDisplay = act.NoticeReplaced; break; default: v.TextToDisplay = act.SyncMatch != null && act.SyncMatch.Success ? act.SyncMatch.Result(v.Text) : v.Text; break; } if (string.IsNullOrEmpty(v.TextToDisplay)) { continue; } v.TextToDisplay = TimelineExpressionsModel.ReplaceText(v.TextToDisplay); // PC名をルールに従って置換する v.TextToDisplay = XIVPluginHelper.Instance.ReplacePartyMemberName( v.TextToDisplay, Settings.Default.PCNameInitialOnDisplayStyle); WPFHelper.BeginInvoke(async() => { if (v.Delay > 0) { await Task.Delay(TimeSpan.FromSeconds(v.Delay ?? 0)); } TimelineNoticeOverlay.NoticeView?.AddNotice(v); v.SetSyncToHide(placeholders); v.AddSyncToHide(); }); } foreach (var i in inotices) { WPFHelper.BeginInvoke(async() => { if (i.Delay > 0) { await Task.Delay(TimeSpan.FromSeconds(i.Delay ?? 0)); } i.StartNotice(); i.SetSyncToHide(placeholders); i.AddSyncToHide(); }); } }