Hi Tony,
Awesome, thanks for this. The template methods worked like a dream! This will save me hours of time.
For database merging, I found clicking on overwrite, then merge produced a desirable result. I'd rather have redundancy than accidentally overwrite something I didn't mean to, since I plan on going back and forth and testing a lot.
Here's what I ultimately cooked up in case someone else out there is trying to do something similar to me.
Basically at the start of the doc I added a [TITLE] [ACTOR] and [CONVERSANT] tag to define those things at the start.
Like this
[TITLE]Captain crunch's dilemma
[ACTOR]Captain Crunch
[CONVERSANT]Parrot
Placing @ at the beginning of a line indicates it's an actor, the next line gets turned into dialogue text.
If the actor isn't already in the database, it creates a new actor on the spot.
Thanks again!
Code: Select all
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using UnityEngine;
using UnityEditor;
namespace PixelCrushers.DialogueSystem
{
//*** Rename TemplateConverterPrefs here and in the ConverterWindowTemplate class definition below.
[Serializable]
public class FountainConverterPrefs : AbstractConverterWindowPrefs
{
//*** Add any settings your window needs to remember here.
}
//*** Rename ConverterWindowTemplate to the name of your converter class:
public class FountainConverterWindowTemplate : AbstractConverterWindow<FountainConverterPrefs>
{
//*** Set the source file extension here:
//7-21-23 : changed "txt" to "fountain"
public override string sourceFileExtension { get { return "fountain"; } }
//*** Set the EditorPrefs key to save preferences under:
//7-21-23 : changed to "PixelCrushers.DialogueSystem.FountainConverterSettings"
public override string prefsKey { get { return "PixelCrushers.DialogueSystem.FountainConverterSettings"; } }
//*** Customize this menu item:
[MenuItem("Tools/Pixel Crushers/Dialogue System/Import/Fountain", false, 1)]
public static void Init()
{
EditorWindow.GetWindow(typeof(FountainConverterWindowTemplate), false, "Fountain Import");
}
//*** Basic preferences are stored in a variable named 'prefs' of type Prefs. You can
//*** create a subclass of Prefs if you need to store additional data. If you do this,
//*** also override the ClearPrefs(), LoadPrefs(), and SavePrefs() methods.
//*** This is the main conversion routine.
//*** Read prefs.SourceFile (or whatever source data you need, if you've overridden
//*** the prefs object) and copy the data into the dialogue database object.
protected override void CopySourceToDialogueDatabase(DialogueDatabase database)
{
//Load the source file
LoadSourceFile();
Debug.Log("FountainConverterWindowTemplate : LoadSourceFile() ran!");
string thisTitle = "Untitled Conversation";//the title of the conversation (default, assigned below)
string s_thisActor = "Player";
string s_thisConversant = "NPC";
//---------- Find and add [TITLE]
for (int i = 0; i < sourceLines.Count; i++)//iterate through source
{
if (sourceLines[i].StartsWith("[TITLE]"))
{
string titleMarkedString = sourceLines[i];
string foundTitle = titleMarkedString.Remove(0, 7);//define foundTitle, remove [TITLE] markup
thisTitle = foundTitle;
Debug.Log("FountainConverterWindowTemplate : Title = " + thisTitle);
break;
}
}
//---------- Find and add [ACTOR]
for (int i = 0; i < sourceLines.Count; i++)//iterate
{
if (sourceLines[i].StartsWith("[ACTOR]"))
{
//check if it exists, if not - make a new one.
string actorMarkedString = sourceLines[i];
string foundActor = actorMarkedString.Remove(0, 7);
s_thisActor = foundActor;
if (database.GetActor(s_thisActor) == null)//Check if the actor already exists. if not, add a new one.
{
int actorID = template.GetNextActorID(database);
bool isThisPlayer = false;
//if (s_thisActor == "JOHNBOY") { isThisPlayer = true; }//check if it's player
Actor newActor = template.CreateActor(actorID, s_thisActor, isThisPlayer);//create new actor
database.actors.Add(newActor);//Add to Dialogue System Database
Debug.Log("FountainConverterWindowTemplate : New Actor created : " + s_thisActor + " | Actor ID = " + newActor.id);
}
break;
}
}
//---------- Find and add [CONVERSANT]
for (int i = 0; i < sourceLines.Count; i++)//iterate
{
if (sourceLines[i].StartsWith("[CONVERSANT]"))
{
string conversantMarkedString = sourceLines[i];
string foundConversant = conversantMarkedString.Remove(0, 12);
s_thisConversant = foundConversant;
if (database.GetActor(s_thisConversant) == null)
{
int actorID = template.GetNextActorID(database);
bool isThisPlayer = false;
//if (s_thisActor == "JOHNBOY") { isThisPlayer = true; }//check if it's player
Actor newActor = template.CreateActor(actorID, s_thisConversant, isThisPlayer);//create new actor
database.actors.Add(newActor);
Debug.Log("FountainConverterWindowTemplate : New Actor created : " + s_thisConversant + " | Actor ID = " + newActor.id);
}
break;
}
}
//Define conversationID and new conversation. Add title, actor, and conversant.
int conversationID = template.GetNextConversationID(database);
Conversation newConversation = template.CreateConversation(conversationID, thisTitle);
newConversation.ActorID = Tools.StringToInt(s_thisActor);
newConversation.ConversantID = Tools.StringToInt(s_thisConversant);
Debug.Log("FountainConverterWindowTemplate : New Conversation Created!");
//Create the <START> entry:
DialogueEntry startEntry = template.CreateDialogueEntry(0, conversationID, "START");
newConversation.dialogueEntries.Add(startEntry);//Add startEntry to newConversation
DialogueEntry prevEntry = startEntry;//Placeholder for prevEntry
string currentActor = s_thisActor;
string currentConversant = s_thisConversant;
string previousActor = s_thisConversant;
string previousConversant = s_thisActor;
Debug.Log("FountainConverterWindowTemplate : for Loop Started, " + sourceLines.Count + " source lines in fountan file!");
//Iterate through source file, every time an @ is detected,
for (int i = 0; i < sourceLines.Count; i++)
{
if (sourceLines[i].StartsWith("@"))
{
string actorMarkedString = sourceLines[i];
string actorName = actorMarkedString.Remove(0, 1);//Define actorName, remove @ markup
//If the actor is different than last time, change the actor/conversant. If it's a new actor, add them.
if (currentActor != actorName)//if the actor is different
{
//check if current actor is not previous speaker, and if currentActor is already in database
if(actorName != previousConversant && database.GetActor(actorName) != null)
{
//assign new current actor. Previous conversant.
previousActor = currentActor;
previousConversant = currentConversant;
currentActor = actorName;
currentConversant = previousActor; //(is this enough?)
Debug.Log("FountainConverterWindowTemplate : Current Actor = " + currentActor + " | Current Conversant = " + currentConversant);
Debug.Log("FountainConverterWindowTemplate : Previous Actor = " + previousActor + " | Previous Conversant = " + previousConversant);
}
else if(actorName != previousConversant && database.GetActor(actorName) == null)//if currentActor is NOT in database
{
//Add the new actor, than assign new current actor. Previous conversant.
int actorID = template.GetNextActorID(database);
Actor newActor = template.CreateActor(actorID, actorName, false);
database.actors.Add(newActor);
previousActor = currentActor;
previousConversant = currentConversant;
currentActor = actorName;
currentConversant = previousActor;
Debug.Log("FountainConverterWindowTemplate : Current Actor = " + currentActor + " | Current Conversant = " + currentConversant);
Debug.Log("FountainConverterWindowTemplate : Previous Actor = " + previousActor + " | Previous Conversant = " + previousConversant);
}
else
{
//swap previous/current actor/conversant (2 way convo)
previousActor = currentActor;
previousConversant = currentConversant;
currentActor = actorName;
currentConversant = previousActor;
Debug.Log("FountainConverterWindowTemplate : Current Actor = " + currentActor + " | Current Conversant = " + currentConversant);
Debug.Log("FountainConverterWindowTemplate : Previous Actor = " + previousActor + " | Previous Conversant = " + previousConversant);
}
}
string dialogueText = sourceLines[i + 1];//Define dialogue text (the next line down)
int entryID = template.GetNextDialogueEntryID(newConversation);//Define entryID from newConversation
DialogueEntry entry = template.CreateDialogueEntry(entryID, conversationID, ""); //create new dialogue entry
entry.ActorID = database.GetActor(currentActor).id;//Assign actorID and conversantID
entry.ConversantID = database.GetActor(currentConversant).id;
entry.DialogueText = dialogueText;//assign dialogue text to entry
newConversation.dialogueEntries.Add(entry);//add entry to conversation
Debug.Log("FountainConverterWindowTemplate : " + actorName + " : " + dialogueText);
//Debug.Log("FountainConverterWindowTemplate : entry actor/conversant check: actor = " + entry.ActorID + " conversant = " + entry.ConversantID);
//Link previous entry to this entry:
prevEntry.outgoingLinks.Add(new Link(conversationID, prevEntry.id, conversationID, entry.id));
prevEntry = entry;//shift prev entry to this entry
}
}
//add newConversation to database
database.AddConversation(newConversation);
Debug.Log("FountainConverterWindowTemplate : Conversation added to Database!");
}
//*** Uncomment this method and change it if you want to change the way the converter
//*** touches up the database after copying the source data. The base version of this
//*** method edits the START nodes of all conversations and sets their Sequence fields
//*** to None(). For example, if you know where the actors' portrait textures are,
//*** You can also call FindPortraitTextures(database, portraitFolder), which will
//*** assign the actors' portrait images based on their Textures fields.
//protected override void TouchUpDialogueDatabase(DialogueDatabase database) {
// base.TouchUpDialogueDatabase(database);
//}
//*** This is a subclass of AbstractConverterWindow. All methods in AbstractConverterWindow
//*** are overrideable, so you can really customize it however you want by overriding
//*** specific methods.
}
}