예제 #1
0
        /// <summary>
        /// Compiles the story at `storyPath` with bookmark at `bookmarkPath` to `targetPath`.
        /// Generates a constants file and saves it to the Kataru source directory.
        /// </summary>
        /// <param name="storyPath"></param>
        /// <param name="bookmarkPath"></param>
        /// <param name="targetPath"></param>
        /// <param name="codegenPath"></param>
        public static void Compile(string storyPath, string bookmarkPath, string targetPath, string codegenPath)
        {
            Debug.Log($@"Runner.Compile(storyPath: '{storyPath}'
                bookmarkPath: '{bookmarkPath}'
                targetPath: '{targetPath}'
                codegenPath: '{codegenPath}')");
            try
            {
                FFI.LoadStory(storyPath);
                FFI.LoadBookmark(bookmarkPath);
                FFI.Validate();

                Debug.Log($"Story at '{storyPath}' validated. Saving compiled story to '{targetPath}'.");
                FFI.SaveStory(targetPath);
                FFI.CodegenConsts(codegenPath);

                // Force unity to recompile using the newly generated source code.
                if (FFI.CodegenWasUpdated())
                {
                    Debug.Log($"Constants file generated at {targetPath}");
                    UnityEditor.Compilation.CompilationPipeline.RequestScriptCompilation();
                }
            }
            catch (System.EntryPointNotFoundException e)
            {
                Debug.LogError($"Kataru error: could not find FFI command named '{e.Message}'");
            }
            catch (Exception e)
            {
                Debug.LogError($"Kataru error: {e.ToString()}");
            }
        }
예제 #2
0
        /// <summary>
        /// Initialize the story, bookmark and internal runner.
        /// This method should only be called once.
        /// </summary>
        public static void Init()
        {
            isInitialized = false;
            var settings = KataruSettings.Get(createIfMissing: true);

            targetPath   = Application.streamingAssetsPath + "/" + settings.targetPath;
            bookmarkPath = Application.streamingAssetsPath + "/" + settings.bookmarkPath;
            savePath     = Application.persistentDataPath + "/" + settings.savePath;
            codegenPath  = settings.codegenPath;

            Debug.Log(
                $@"Kataru.Init(StoryPath: '{targetPath}', 
                BookmarkPath: '{bookmarkPath}', 
                SavePath: '{savePath}')");

#if UNITY_EDITOR
            if (!File.Exists(targetPath))
            {
                Debug.LogWarning("Missing target. Retriggering compilation...");
                storyPath = Application.dataPath + "/" + settings.storyPath;

                Compile(storyPath, bookmarkPath, targetPath, codegenPath);
            }
#endif

            isRunning = false;
            isWaiting = false;

            // Only load the story on Init.
            FFI.LoadStory(targetPath);

            isInitialized = true;
        }
예제 #3
0
        /// <summary>
        /// Save the bookmark to save path.
        /// </summary>
        public static void Save()
        {
            if (!isInitialized)
            {
                Debug.LogError($"Have not initialized. Call Runner.Init() before calling this.");
                return;
            }

            var parent = Directory.GetParent(savePath);

            if (!parent.Exists)
            {
                parent.Create();
            }
#if UNITY_EDITOR
            Debug.Log($"Kataru.Save('{savePath}')");
#endif
            FFI.SaveBookmark(savePath);
        }
예제 #4
0
        /// <summary>
        /// Load bookmark from the save path path.
        /// Call this when wanting to load save file.
        /// </summary>
        public static void Load()
        {
            if (!isInitialized)
            {
                Debug.LogError($"Have not initialized. Call Runner.Init() before calling this.");
                return;
            }

            if (SaveExists())
            {
                FFI.LoadBookmark(savePath);
            }
            else
            {
                Debug.Log($"Loading bookmark {bookmarkPath}");
                FFI.LoadBookmark(bookmarkPath);
            }

            Debug.Log("Initializing runner...");
            FFI.InitRunner();
        }
예제 #5
0
        /// <summary>
        /// Progress the story using the given input.
        /// This yields line data from internal dialogue runner, whose data is passed via invoking actions.
        /// If delayed next was called previously, this runner is current waiting for that to finish and won't run the next line.
        /// </summary>
        /// <param name="input"></param>
        public static LineTag Next(string input = "", bool auto = false)
        {
#if UNITY_EDITOR
            string caller = (new System.Diagnostics.StackTrace()).GetFrame(auto ? 2 : 1).GetMethod().Name;
            Debug.Log($"Kataru.Runner.Next('{input}') from {caller}.");
#endif
            if (isWaiting)
            {
#if UNITY_EDITOR
                Debug.LogWarning($@"Called Runner.Next while runner was busy waiting.
                                    Don't call Runner.Next until Runner.DelayedNext has finished.");
#endif
                return(LineTag.End);
            }

            FFI.Next(input);
            Tag = FFI.Tag();
#if UNITY_EDITOR
            Debug.Log($"Tag: {Tag}");
#endif
            switch (Tag)
            {
            case LineTag.Choices:
                OnChoices.Invoke(FFI.LoadChoices());
                break;

            case LineTag.InvalidChoice:
                OnInvalidChoice.Invoke();
                break;

            case LineTag.Dialogue:
                Dialogue dialogue = FFI.LoadDialogue();
#if UNITY_EDITOR
                Debug.Log($"{dialogue.name}: '{dialogue.text}'");
#endif
                CharacterDelegates.Invoke(dialogue.name, new object[] { dialogue });
                break;

            case LineTag.Command:
                Command command = FFI.GetCommand();
#if UNITY_EDITOR
                Debug.Log($"Calling command '{command.name}'");
                if (string.IsNullOrEmpty(command.name))
                {
                    throw new KeyNotFoundException($"Received empty Kataru command. Did you use a global command as a character command?");
                }
#endif
                ConcurrentDictionary <Delegate, bool> delegates;
                if (CommandDelegates.TryGetValue(command.name, out delegates))
                {
                    object[] @params = new object[] { };
                    foreach (var @delegate in delegates.Keys)
                    {
                        @params = command.Params(@delegate.Method);
                        break;
                    }
                    CommandDelegates.Invoke(command.name, @params);
                }
                else
                {
                    throw new KeyNotFoundException($"No Kataru command named '{command.name}' was registered in Unity. Are you missing a command definition, attribute, or reference?");
                }
                break;

            case LineTag.InputCommand:
                OnInputCommand?.Invoke(FFI.LoadInputCommand());
                break;

            case LineTag.End:
                Exit();
                break;
            }
            OnLine?.Invoke(Tag);
            return(Tag);
        }
예제 #6
0
 public static string GetPassage() => FFI.GetPassage();
예제 #7
0
 public static void SetState(string key, bool value) => FFI.SetState(key, value);
예제 #8
0
 public static void SetState(string key, double value) => FFI.SetState(key, value);
예제 #9
0
 public static void GotoPassage(string passage) => FFI.GotoPassage(passage);
예제 #10
0
 public static void SetLine(int line) => FFI.SetLine(line);
예제 #11
0
 public static void LoadSnapshot(string name) => FFI.LoadSnapshot(name);
예제 #12
0
 public static void SaveSnapshot(string name) => FFI.SaveSnapshot(name);