/// <summary> /// Fills the dialog placeholders /// </summary> /// <param name="code">Code</param> /// <param name="npc">Npc</param> /// <returns>Filled code</returns> private async Task <string> FillDialogPlaceholders(string code, KortistoNpc npc) { GoNorthProject project = await _cachedDbAccess.GetDefaultProject(); TaleDialog dialog = await _taleDbAccess.GetDialogByRelatedObjectId(npc.Id); try { _errorCollection.CurrentErrorContext = _localizer["DialogErrorContext"].Value; _dialogParser.SetErrorCollection(_errorCollection); _dialogRenderer.SetErrorCollection(_errorCollection); ExportDialogData exportDialog = null; bool hasValidDialog = HasValidDialog(dialog); if (hasValidDialog) { exportDialog = _dialogParser.ParseDialog(dialog); if (exportDialog == null) { return(string.Empty); } exportDialog = await _dialogFunctionGenerator.GenerateFunctions(project.Id, npc.Id, exportDialog, _errorCollection); } code = ExportUtil.RenderPlaceholderIfTrue(code, Placeholder_HasDialog_Start, Placeholder_HasDialog_End, hasValidDialog); code = await RenderDialog(project, code, exportDialog, dialog, npc); } finally { _errorCollection.CurrentErrorContext = ""; } return(code); }
public async Task <IActionResult> FlagDialogAsImplemented(string dialogId) { // Check Data TaleDialog dialog = await _dialogDbAccess.GetDialogById(dialogId); if (dialog == null) { return(StatusCode((int)HttpStatusCode.NotFound)); } // Flag dialog as implemented dialog.IsImplemented = true; await _dialogSnapshotDbAccess.SaveSnapshot(dialog); await _dialogDbAccess.UpdateDialog(dialog); // Add Timeline entry List <KortistoNpc> npcNames = await _npcDbAccess.ResolveFlexFieldObjectNames(new List <string> { dialog.RelatedObjectId }); string npcName = ""; if (npcNames.Count > 0) { npcName = npcNames[0].Name; } await _timelineService.AddTimelineEntry(TimelineEvent.ImplementedDialog, dialog.RelatedObjectId, npcName); return(Ok()); }
/// <summary> /// Deletes additional depencendies for a flex field object /// </summary> /// <param name="flexFieldObject">Flex field object to delete</param> /// <returns>Task</returns> protected override async Task DeleteAdditionalFlexFieldObjectDependencies(KortistoNpc flexFieldObject) { TaleDialog dialog = await _taleDbAccess.GetDialogByRelatedObjectId(flexFieldObject.Id); if (dialog != null) { await _taleDbAccess.DeleteDialog(dialog); } _logger.LogInformation("Dialog was deleted."); }
/// <summary> /// Compares a dialog /// </summary> /// <param name="dialogId">Id of the dialog</param> /// <param name="currentDialog">Current dialog, if null the dialog will be loaded</param> /// <returns>Compare Result</returns> public async Task <CompareResult> CompareDialog(string dialogId, TaleDialog currentDialog = null) { if (currentDialog == null) { currentDialog = await _dialogDbAccess.GetDialogById(dialogId); } TaleDialog oldDialog = await _dialogSnapshotDbAccess.GetSnapshotById(dialogId); return(CompareObjects(currentDialog, oldDialog)); }
public async Task <IActionResult> IsDialogImplementedByRelatedObjectId(string relatedObjectId) { DialogImplementedResponse response = new DialogImplementedResponse(); TaleDialog dialog = await _taleDbAccess.GetDialogByRelatedObjectId(relatedObjectId); if (dialog != null) { response.Exists = true; response.IsImplemented = dialog.IsImplemented; } return(Ok(response)); }
/// <summary> /// Returns true if a valid dialog exists, else false /// </summary> /// <param name="dialog">Dialog to check</param> /// <returns>true if a valid dialog exists, else false</returns> private bool HasValidDialog(TaleDialog dialog) { if (dialog == null) { return(false); } if (!dialog.NpcText.Any() && !dialog.PlayerText.Any() && !dialog.Choice.Any() && !dialog.Condition.Any() && !dialog.Action.Any()) { return(false); } return(true); }
/// <summary> /// Parses a dialog for exporting /// </summary> /// <param name="dialog">Dialog to parse</param> /// <returns>Parsed dialog</returns> public ExportDialogData ParseDialog(TaleDialog dialog) { _currentNodeIndex = 0; ExportDialogData exportDialog = SearchDialogRootNode(dialog); if (exportDialog == null) { return(null); } IterateDialogTree(exportDialog, dialog); EnsureNoInfinityLoopExists(exportDialog); return(exportDialog); }
/// <summary> /// Searches the dialog root node /// </summary> /// <param name="dialog">Dialog to search</param> /// <returns>Dialog root node</returns> private ExportDialogData SearchDialogRootNode(TaleDialog dialog) { List <ExportDialogData> rootNodes = new List <ExportDialogData>(); rootNodes.AddRange(GetRootNodesFromList(dialog.PlayerText, dialog.Link, (e, n) => e.PlayerText = n)); rootNodes.AddRange(GetRootNodesFromList(dialog.NpcText, dialog.Link, (e, n) => e.NpcText = n)); rootNodes.AddRange(GetRootNodesFromList(dialog.Choice, dialog.Link, (e, n) => e.Choice = n)); rootNodes.AddRange(GetRootNodesFromList(dialog.Action, dialog.Link, (e, n) => e.Action = n)); rootNodes.AddRange(GetRootNodesFromList(dialog.Condition, dialog.Link, (e, n) => e.Condition = n)); if (rootNodes.Count != 1) { _errorCollection.AddDialogRootNodeCountNotOne(rootNodes.Count); return(null); } return(rootNodes.First()); }
/// <summary> /// Collects the values for an export /// </summary> /// <param name="templateType">Template type</param> /// <param name="parsedTemplate">Parsed scriban template</param> /// <param name="scriptObject">Scriban script object to fill</param> /// <param name="data">Export Data</param> /// <returns>Task</returns> public override async Task CollectValues(TemplateType templateType, Template parsedTemplate, ScriptObject scriptObject, ExportObjectData data) { KortistoNpc inputNpc = data.ExportData[ExportConstants.ExportDataObject] as KortistoNpc; if (inputNpc == null) { return; } _languageKeyGenerator.SetErrorCollection(_errorCollection); GoNorthProject project = await _exportCachedDbAccess.GetUserProject(); TaleDialog dialog = await _taleDbAccess.GetDialogByRelatedObjectId(inputNpc.Id); ExportDialogData parsedDialog = await ParseDialog(inputNpc, project, dialog); ScribanExportDialog exportDialog = await BuildExportDialog(parsedDialog, inputNpc); scriptObject.AddOrUpdate(ExportConstants.ScribanDialogKey, exportDialog); scriptObject.AddOrUpdate(DialogFunctionRenderer.DialogFunctionName, new DialogFunctionRenderer(_templatePlaceholderResolver, _exportCachedDbAccess, _defaultTemplateProvider, _errorCollection, data)); }
/// <summary> /// Iterates the dialog tree /// </summary> /// <param name="exportDialog">Export Dialog Data at the moment</param> /// <param name="dialog">Dialog</param> private void IterateDialogTree(ExportDialogData exportDialog, TaleDialog dialog) { Dictionary <string, ExportDialogData> convertedDialogNodes = new Dictionary <string, ExportDialogData>(); convertedDialogNodes.Add(exportDialog.Id, exportDialog); Queue <ExportDialogData> dialogDataToQueue = new Queue <ExportDialogData>(); dialogDataToQueue.Enqueue(exportDialog); while (dialogDataToQueue.Any()) { ExportDialogData curData = dialogDataToQueue.Dequeue(); List <ExportDialogDataChild> children = FindDialogElementChildren(convertedDialogNodes, curData, dialog); if (curData.Choice != null) { children = SortChildrenByChoices(children, curData.Choice); } else if (curData.Condition != null) { children = SortChildrenByConditions(children, curData.Condition); } curData.Children.AddRange(children); foreach (ExportDialogDataChild curChild in children) { curChild.Child.Parents.Add(curData); if (!convertedDialogNodes.ContainsKey(curChild.Child.Id)) { dialogDataToQueue.Enqueue(curChild.Child); convertedDialogNodes.Add(curChild.Child.Id, curChild.Child); } } } }
/// <summary> /// Finds the children of da dialog element /// </summary> /// <param name="convertedDialogNodes">Already converted nodes</param> /// <param name="dialogData">Dialog data whichs children are searched</param> /// <param name="dialog">Dialog</param> /// <returns>Children of the element</returns> private List <ExportDialogDataChild> FindDialogElementChildren(Dictionary <string, ExportDialogData> convertedDialogNodes, ExportDialogData dialogData, TaleDialog dialog) { List <NodeLink> childLinks = dialog.Link.Where(l => l.SourceNodeId == dialogData.Id).ToList(); List <ExportDialogDataChild> childNodes = new List <ExportDialogDataChild>(); childNodes.AddRange(FindDialogElementChildrenInList(convertedDialogNodes, dialog.PlayerText, childLinks, (e, n) => e.PlayerText = n)); childNodes.AddRange(FindDialogElementChildrenInList(convertedDialogNodes, dialog.NpcText, childLinks, (e, n) => e.NpcText = n)); childNodes.AddRange(FindDialogElementChildrenInList(convertedDialogNodes, dialog.Choice, childLinks, (e, n) => e.Choice = n)); childNodes.AddRange(FindDialogElementChildrenInList(convertedDialogNodes, dialog.Action, childLinks, (e, n) => e.Action = n)); childNodes.AddRange(FindDialogElementChildrenInList(convertedDialogNodes, dialog.Condition, childLinks, (e, n) => e.Condition = n)); return(childNodes); }
/// <summary> /// Renders the dialog /// </summary> /// <param name="project">Current Project</param> /// <param name="code">Template code</param> /// <param name="exportDialog">Export dialog data</param> /// <param name="dialog">Dialog</param> /// <param name="npc">Npc to which the dialog belongs</param> /// <returns>Filled code</returns> private async Task <string> RenderDialog(GoNorthProject project, string code, ExportDialogData exportDialog, TaleDialog dialog, KortistoNpc npc) { if (exportDialog == null) { code = ExportUtil.BuildPlaceholderRegex(Placeholder_Start).Replace(code, string.Empty); code = ExportUtil.BuildPlaceholderRegex(Placeholder_Additional_Functions).Replace(code, string.Empty); return(code); } ExportDialogRenderResult dialogRenderResult = await _dialogRenderer.RenderDialog(exportDialog, npc); code = ExportUtil.BuildPlaceholderRegex(Placeholder_Start, ExportConstants.ListIndentPrefix).Replace(code, m => { return(ExportUtil.TrimEmptyLines(ExportUtil.IndentListTemplate(dialogRenderResult.StartStepCode, m.Groups[1].Value))); }); code = ExportUtil.BuildPlaceholderRegex(Placeholder_Additional_Functions, ExportConstants.ListIndentPrefix).Replace(code, m => { return(ExportUtil.TrimEmptyLines(ExportUtil.IndentListTemplate(dialogRenderResult.AdditionalFunctionsCode, m.Groups[1].Value))); }); return(code); }
/// <summary> /// Renders the dialog /// </summary> /// <param name="project">Current Project</param> /// <param name="code">Template code</param> /// <param name="exportDialog">Export dialog data</param> /// <param name="dialog">Dialog</param> /// <param name="npc">Npc to which the dialog belongs</param> /// <returns>Filled code</returns> private async Task <string> RenderDialog(GoNorthProject project, string code, ExportDialogData exportDialog, TaleDialog dialog, KortistoNpc npc) { if (exportDialog == null) { code = ExportUtil.BuildPlaceholderRegex(Placeholder_Start).Replace(code, string.Empty); code = ExportUtil.BuildPlaceholderRegex(Placeholder_Additional_Functions).Replace(code, string.Empty); return(code); } List <ExportDialogFunctionCode> dialogRenderResult = await _dialogRenderer.RenderDialogSteps(exportDialog, npc); code = ExportUtil.BuildPlaceholderRegex(Placeholder_Start, ExportConstants.ListIndentPrefix).Replace(code, m => { if (dialogRenderResult.Any()) { return(ExportUtil.TrimEmptyLines(ExportUtil.IndentListTemplate(dialogRenderResult[0].Code, m.Groups[1].Value))); } return(string.Empty); }); code = await ExportUtil.BuildPlaceholderRegex(Placeholder_Additional_Functions, ExportConstants.ListIndentPrefix).ReplaceAsync(code, async m => { string finalCode = string.Empty; foreach (ExportDialogFunctionCode curFunction in dialogRenderResult.Skip(1)) { finalCode += await RenderFunctionForList(project, curFunction); } return(ExportUtil.TrimEmptyLines(ExportUtil.IndentListTemplate(finalCode, m.Groups[1].Value))); }); return(code); }
public async Task <IActionResult> GetDialogByRelatedObjectId(string relatedObjectId) { TaleDialog dialog = await _taleDbAccess.GetDialogByRelatedObjectId(relatedObjectId); return(Ok(dialog)); }
public async Task <IActionResult> SaveDialog(string relatedObjectId, [FromBody] TaleDialog dialog) { // Validate data if (string.IsNullOrEmpty(relatedObjectId)) { return(BadRequest()); } List <KortistoNpc> npcNames = await _npcDbAccess.ResolveFlexFieldObjectNames(new List <string> { relatedObjectId }); if (npcNames.Count == 0) { return(BadRequest()); } string npcName = npcNames[0].Name; // Update or create dialog TaleDialog existingDialog = await _taleDbAccess.GetDialogByRelatedObjectId(relatedObjectId); bool isCreate = false; if (existingDialog == null) { KortistoNpc npc = await _npcDbAccess.GetFlexFieldObjectById(relatedObjectId); existingDialog = new TaleDialog(); existingDialog.RelatedObjectId = relatedObjectId; existingDialog.ProjectId = npc.ProjectId; isCreate = true; } existingDialog.Link = dialog.Link != null ? dialog.Link : new List <NodeLink>(); existingDialog.PlayerText = dialog.PlayerText != null ? dialog.PlayerText : new List <TextNode>(); existingDialog.NpcText = dialog.NpcText != null ? dialog.NpcText : new List <TextNode>(); existingDialog.Choice = dialog.Choice != null ? dialog.Choice : new List <TaleChoiceNode>(); existingDialog.Action = dialog.Action != null ? dialog.Action : new List <ActionNode>(); existingDialog.Condition = dialog.Condition != null ? dialog.Condition : new List <ConditionNode>(); existingDialog.Reference = dialog.Reference != null ? dialog.Reference : new List <ReferenceNode>(); await this.SetModifiedData(_userManager, existingDialog); // Save Data if (isCreate) { existingDialog = await _taleDbAccess.CreateDialog(existingDialog); await _timelineService.AddTimelineEntry(existingDialog.ProjectId, TimelineEvent.TaleDialogCreated, relatedObjectId, npcName); } else { // Check implementation state if (existingDialog.IsImplemented) { CompareResult result = await _implementationStatusComparer.CompareDialog(existingDialog.Id, existingDialog); if (result.CompareDifference != null && result.CompareDifference.Count > 0) { existingDialog.IsImplemented = false; } } await _taleDbAccess.UpdateDialog(existingDialog); await _timelineService.AddTimelineEntry(existingDialog.ProjectId, TimelineEvent.TaleDialogUpdated, relatedObjectId, npcName); } return(Ok(existingDialog)); }
/// <summary> /// Exports an object /// </summary> /// <param name="exportFormat">Format to export (Script, JSON or LanguageFile)</param> /// <param name="id">Id of the object to export</param> /// <param name="templateType">Template type</param> /// <returns>Export result</returns> private async Task <ExportObjectResult> RunExportObject(string exportFormat, string id, TemplateType templateType) { // Check Access if ((templateType == TemplateType.ObjectNpc && !User.IsInRole(RoleNames.Kortisto)) || (templateType == TemplateType.ObjectItem && !User.IsInRole(RoleNames.Styr)) || (templateType == TemplateType.ObjectSkill && !User.IsInRole(RoleNames.Evne))) { throw new UnauthorizedAccessException(); } // Get Exporter string exporterKey = exportFormat.ToLowerInvariant(); if (!_exporters.ContainsKey(exporterKey)) { throw new InvalidOperationException("Unknown Export Format"); } IObjectExporter exporter = _exporters[exporterKey]; // Get Objects bool objectFound = false; ExportObjectData objectData = new ExportObjectData(); if (templateType == TemplateType.ObjectNpc) { KortistoNpc npc = await _npcDbAccess.GetFlexFieldObjectById(id); if (npc != null) { objectData.ExportData.Add(ExportConstants.ExportDataObject, npc); objectData.ExportData.Add(ExportConstants.ExportDataObjectType, ExportConstants.ExportObjectTypeNpc); TaleDialog dialog = await _dialogDbAccess.GetDialogByRelatedObjectId(id); objectData.ExportData.Add(ExportConstants.ExportDataDialog, dialog); objectFound = true; } } else if (templateType == TemplateType.ObjectItem) { StyrItem item = await _itemDbAccess.GetFlexFieldObjectById(id); if (item != null) { objectData.ExportData.Add(ExportConstants.ExportDataObject, item); objectData.ExportData.Add(ExportConstants.ExportDataObjectType, ExportConstants.ExportObjectTypeItem); objectFound = true; } } else if (templateType == TemplateType.ObjectSkill) { EvneSkill skill = await _skillDbAccess.GetFlexFieldObjectById(id); if (skill != null) { objectData.ExportData.Add(ExportConstants.ExportDataObject, skill); objectData.ExportData.Add(ExportConstants.ExportDataObjectType, ExportConstants.ExportObjectTypeSkill); objectFound = true; } } else { throw new InvalidOperationException("Template Type not supported for exporting"); } if (!objectFound) { throw new KeyNotFoundException(); } // Get Template ExportTemplateByObjectIdResult template = await GetValidExportTemplateByIdAndType(id, templateType); // Run Export ExportObjectResult result = await exporter.ExportObject(template.Template, objectData); result.ObjectFilename = ((FlexFieldObject)objectData.ExportData[ExportConstants.ExportDataObject]).Name; string regexSearch = Regex.Escape(new string(Path.GetInvalidFileNameChars())); Regex illegalCharRegex = new Regex(string.Format("[{0}]", regexSearch)); result.ObjectFilename = illegalCharRegex.Replace(result.ObjectFilename, string.Empty); return(result); }
/// <summary> /// Parses a dialog /// </summary> /// <param name="inputNpc">Input npc</param> /// <param name="project">Project</param> /// <param name="dialog">Dialog</param> /// <returns>Export dialog data</returns> private async Task <ExportDialogData> ParseDialog(KortistoNpc inputNpc, GoNorthProject project, TaleDialog dialog) { ExportDialogData parsedDialog = null; IStringLocalizer localizer = _localizerFactory.Create(typeof(DialogValueCollector)); try { _errorCollection.CurrentErrorContext = localizer["DialogErrorContext"].Value; _dialogParser.SetErrorCollection(_errorCollection); _dialogRenderer.SetErrorCollection(_errorCollection); bool hasValidDialog = SharedDialogExportUtil.HasValidDialog(dialog); if (hasValidDialog) { parsedDialog = _dialogParser.ParseDialog(dialog); if (parsedDialog != null) { parsedDialog = await _dialogFunctionGenerator.GenerateFunctions(project.Id, inputNpc.Id, parsedDialog, _errorCollection); } } } finally { _errorCollection.CurrentErrorContext = ""; } return(parsedDialog); }