示例#1
0
    // ********************************************************************
    public void AddFrameAt(DialogueFrame _frame, int _pos)
    {
        // Add cue
        frames.Insert(_pos, _frame);
        _frame.conversation = this;
        _frame.expanded     = true;

        // Set dirty
        EditorUtility.SetDirty(this);

        // Create the asset and add it to the project
        string parentFolder = Path.GetDirectoryName(AssetDatabase.GetAssetPath(this));
        string assetPath    = parentFolder + "/Frames";

        if (!AssetDatabase.IsValidFolder(assetPath))
        {
            string newFolderID = AssetDatabase.CreateFolder(parentFolder, "Frames");
            assetPath = AssetDatabase.GUIDToAssetPath(newFolderID);
        }
        string assetPathAndName       = assetPath + "/DF-" + _frame.id + ".asset";
        string uniqueAssetPathAndName = AssetDatabase.GenerateUniqueAssetPath(assetPathAndName);

        AssetDatabase.CreateAsset(_frame, uniqueAssetPathAndName);
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }
示例#2
0
 public void nextDialogueFrame()
 {
     if (dialogue.Count == 0)
     {
         currentFrame = null;
         return;
     }
     else
     {
         //get next frame
         lastFrame    = currentFrame;
         currentFrame = dialogue.Dequeue();
         if (dialogue.Count > 0)
         {
             hasNextFrame = true;
             nextFrame    = dialogue.Peek();
         }
         else
         {
             hasNextFrame = false;
         }
         UpdateText();
         UpdateAnimationParameters();
     }
 }
示例#3
0
    // ********************************************************************
    // Function:	StartConversation()
    // Purpose:		Determines a conversation to use and starts it
    // ********************************************************************
    public void StartConversation()
    {
        // Determine correct conversation
        if (m_conversations.Count == 0)
        {
            Debug.LogError("No conversations loaded!");
        }
        for (int i = 0; i < m_conversations.Count; ++i)
        {
            if (m_conversations[i].autoload && m_conversations[i].MeetsRequirements(ProfileManager.profile))
            {
                m_currentConversation = m_conversations[i];
                Debug.Log("Conversation loaded: " + m_currentConversation.id);
                break;
            }
        }
        if (m_currentConversation == null) // Can't load any conversation!
        {
            Debug.LogError("Don't meet requirements for any conversations!");
            return;
        }

        // Initialize stuff for new conversation
        m_currentFrame = m_currentConversation.frames[m_currentConversation.startingFrame];

        DisplayFrame();
    }
示例#4
0
    // ********************************************************************
    #endregion
    // ********************************************************************


    // ********************************************************************
        #if UNITY_EDITOR
    // ********************************************************************
    public void AddNewFrameAt(int _pos)
    {
        DialogueFrame newFrame = CreateInstance <DialogueFrame>();

        newFrame.allowSkip    = allowSkip;
        newFrame.waitForInput = waitForInput;
        newFrame.id           = name.Replace("DC-", "") + "-" + _pos.ToString();
        AddFrameAt(newFrame, _pos);
    }
示例#5
0
    // ********************************************************************
    public void MoveFrameTo(DialogueFrame _frame, int _index)
    {
        if (_index < 0 || _index >= frames.Count)
        {
            return;
        }
        frames.Remove(_frame);
        frames.Insert(_index, _frame);

        // Set dirty
        EditorUtility.SetDirty(this);
    }
示例#6
0
    // ********************************************************************
    public void RemoveFrame(DialogueFrame _frame)
    {
        frames.Remove(_frame);

        // Set dirty
        EditorUtility.SetDirty(this);

        string pathToDelete = AssetDatabase.GetAssetPath(_frame);

        AssetDatabase.DeleteAsset(pathToDelete);
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }
    public void ContinueDialogue()
    {
        if (dialogueQueue.Count != 0)
        {
            currentFrame = dialogueQueue.Dequeue();
            StopAllCoroutines();

            StartCoroutine("executeFrameCoroutines");
        }
        else
        {
            endDialogue();
        }
    }
示例#8
0
        // ********************************************************************
        private void FollowLink(DialogueFrame _linkedFrame)
        {
            LogManager.Log("DialoguePanel: FollowLink " + _linkedFrame.name,
                           LogCategory.UI,
                           LogSeverity.LOG,
                           "Dialogue",
                           gameObject);

            if (_linkedFrame.conversation != m_currentConversation)
            {
                m_currentConversation = _linkedFrame.conversation;
            }

            m_currentFrame = _linkedFrame;

            StartCoroutine(DisplayFrame());
        }
示例#9
0
        // ********************************************************************
        #endregion
        // ********************************************************************


        // ********************************************************************
        #region Public Methods
        // ********************************************************************
        public bool StartCurrentConversation()
        {
            if (m_currentConversation == null)
            {
                return(false);
            }

            LogManager.Log("DialoguePanel: Starting conversation " + m_currentConversation.name,
                           LogCategory.UI,
                           LogSeverity.LOG,
                           "Dialogue",
                           gameObject);

            m_currentFrame = m_currentConversation.frames[0];

            StartCoroutine(DisplayFrame());

            return(true);
        }
示例#10
0
    private void FollowLink(string _linkedConv, string _linkedFrame)
    {
        Debug.Log("Following link to conv: " + _linkedConv + " frame: " + _linkedFrame);
        if (_linkedConv != null && _linkedConv != "")
        {
            m_currentConversation = m_conversationsMap[_linkedConv];
            m_currentFrame        = m_currentConversation.frames[m_currentConversation.startingFrame];
        }

        if (_linkedFrame != null && _linkedFrame != "")
        {
            m_currentFrame = m_currentConversation.frames[_linkedFrame];
        }

        DisplayFrame();

        if (m_waitingForChoiceInput)
        {
            m_waitingForChoiceInput = false;
            StartCoroutine(HideChoices(true));
        }
    }
示例#11
0
    public static DialogueFrame Load(Dictionary <string, object> JSON, DialogueFrame defaults = null)
    {
        DialogueFrame newObject;

        if (defaults == null)
        {
            newObject = new DialogueFrame();
        }
        else
        {
            newObject = defaults.MemberwiseClone() as DialogueFrame;
        }

        if (JSON.ContainsKey("id"))
        {
            newObject.id = JSON["id"] as string;
        }

        // Links
        if (JSON.ContainsKey("endOnThisFrame"))
        {
            newObject.endOnThisFrame = bool.Parse(JSON["endOnThisFrame"].ToString());
        }
        if (JSON.ContainsKey("displayChoices"))
        {
            newObject.displayChoices = bool.Parse(JSON["displayChoices"].ToString());
        }
        if (JSON.ContainsKey("links"))
        {
            newObject.links = new List <DialogueLink>();
            List <object> lList = JSON["links"] as List <object>;
            foreach (object lEntry in lList)
            {
                DialogueLink newLink = DialogueLink.Load(lEntry as Dictionary <string, object>);
                newObject.links.Add(newLink);
            }
        }

        // Load NPC Settings
        if (JSON.ContainsKey("npcSettings"))
        {
            DialogueNPCSettings npcSettings = DialogueManager.FetchNPCSettings(JSON["npcSettings"] as string);

            if (npcSettings != null)
            {
                Debug.Log("NPC Settings fetched for: " + JSON["npcSettings"] + " - " + npcSettings);
                if (npcSettings.portraitSettings != null)
                {
                    newObject.portraitSettings = npcSettings.portraitSettings.ShallowCopy();
                }
                if (npcSettings.textSettings != null)
                {
                    newObject.textSettings = npcSettings.textSettings.ShallowCopy();
                }
            }
            else
            {
                Debug.LogError("NPC Settings NOT FOUND for: " + JSON["npcSettings"]);
            }
        }

        // Overrides
        if (JSON.ContainsKey("allowSkip"))
        {
            newObject.allowSkip = bool.Parse(JSON["allowSkip"] as string);
        }
        if (JSON.ContainsKey("waitForInput"))
        {
            newObject.waitForInput = bool.Parse(JSON["waitForInput"] as string);
        }
        if (JSON.ContainsKey("portraitSettings"))
        {
            newObject.portraitSettings = DialoguePortraitSettings.Load(JSON["portraitSettings"] as Dictionary <string, object>, newObject.portraitSettings);
        }
        if (JSON.ContainsKey("textSettings"))
        {
            newObject.textSettings = DialogueTextSettings.Load(JSON["textSettings"] as Dictionary <string, object>, newObject.textSettings);
        }

        // Sections
        if (JSON.ContainsKey("sections"))
        {
            newObject.sections = new List <DialogueSection>();
            DialogueSection defaultSection = new DialogueSection();
            defaultSection.portraitSettings = newObject.portraitSettings;
            defaultSection.textSettings     = newObject.textSettings;
            List <object> sList = JSON["sections"] as List <object>;
            foreach (object sEntry in sList)
            {
                DialogueSection newSection = DialogueSection.Load(sEntry as Dictionary <string, object>, defaultSection);
                newObject.sections.Add(newSection);
            }
            Debug.Log("Frame " + newObject.id + " loaded " + newObject.sections.Count + " sections");
        }

        if (newObject.portraitSettings == null)
        {
            Debug.LogError("portraitSettings is null in DialogueFrame");
        }
        if (newObject.textSettings == null)
        {
            Debug.LogError("textSettings is null in DialogueFrame");
        }

        return(newObject);
    }
示例#12
0
    public static DialogueConversation Load(Dictionary <string, object> JSON, DialogueConversation defaults = null)
    {
        DialogueConversation newObject;

        if (defaults == null)
        {
            newObject = new DialogueConversation();
        }
        else
        {
            newObject = defaults.MemberwiseClone() as DialogueConversation;
        }

        if (JSON.ContainsKey("id"))
        {
            newObject.id = JSON["id"] as string;
        }
        if (JSON.ContainsKey("autoload"))
        {
            newObject.autoload = bool.Parse(JSON["autoload"].ToString());
        }

        // Defaults
        if (JSON.ContainsKey("allowSkip"))
        {
            newObject.allowSkip = bool.Parse(JSON["allowSkip"].ToString());
        }
        if (JSON.ContainsKey("waitForInput"))
        {
            newObject.waitForInput = bool.Parse(JSON["waitForInput"].ToString());
        }
        if (JSON.ContainsKey("portraitSettings"))
        {
            newObject.portraitSettings = DialoguePortraitSettings.Load(JSON["portraitSettings"] as Dictionary <string, object>, newObject.portraitSettings);
        }
        if (JSON.ContainsKey("textSettings"))
        {
            newObject.textSettings = DialogueTextSettings.Load(JSON["textSettings"] as Dictionary <string, object>, newObject.textSettings);
        }

        // Requirements
        if (JSON.ContainsKey("requirements"))
        {
            newObject.requirements = new List <DialogueRequirement>();
            List <object> rList = JSON["requirements"] as List <object>;
            foreach (object rEntry in rList)
            {
                DialogueRequirement newRequirement = DialogueRequirement.Load(rEntry as Dictionary <string, object>);
                newObject.requirements.Add(newRequirement);
            }
        }

        // Frames
        if (JSON.ContainsKey("startingFrame"))
        {
            newObject.startingFrame = JSON["startingFrame"] as string;
        }
        if (JSON.ContainsKey("frames"))
        {
            newObject.frames = new Dictionary <string, DialogueFrame>();

            DialogueFrame defaultFrame = new DialogueFrame();
            defaultFrame.portraitSettings = newObject.portraitSettings;
            defaultFrame.textSettings     = newObject.textSettings;
            defaultFrame.allowSkip        = newObject.allowSkip;
            defaultFrame.waitForInput     = newObject.waitForInput;

            DialogueFrame lastFrame           = null;
            bool          lastFrameLinkNeeded = false;

            List <object> fList = JSON["frames"] as List <object>;
            foreach (object fEntry in fList)
            {
                DialogueFrame newFrame = DialogueFrame.Load(fEntry as Dictionary <string, object>, defaultFrame);
                newObject.frames[newFrame.id] = newFrame;

                if (lastFrameLinkNeeded)
                {
                    DialogueLink link = new DialogueLink();
                    link.linkedFrame = newFrame.id;
                    lastFrame.links  = new List <DialogueLink>();
                    lastFrame.links.Add(link);
                    Debug.Log("Frame " + lastFrame.id + " linked to frame " + newFrame.id);
                }

                lastFrameLinkNeeded = (!newFrame.endOnThisFrame && (newFrame.links == null || newFrame.links.Count == 0));
                lastFrame           = newFrame;

                if (newObject.startingFrame == null || newObject.startingFrame == "")
                {
                    newObject.startingFrame = newFrame.id;
                }
            }

            if (lastFrameLinkNeeded)
            {
                lastFrame.endOnThisFrame = true;
            }
            Debug.Log("Conversation " + newObject.id + " loaded " + newObject.frames.Count + " frames");
            Debug.Log("Starting frame: " + newObject.startingFrame);
        }

        if (newObject.portraitSettings == null)
        {
            Debug.LogError("portraitSettings is null in DialogueConversation");
        }
        if (newObject.textSettings == null)
        {
            Debug.LogError("textSettings is null in DialogueConversation");
        }

        return(newObject);
    }
示例#13
0
 // ********************************************************************
 public void MoveFrame(DialogueFrame _frame, int _move)
 {
     MoveFrameTo(_frame, frames.IndexOf(_frame) + _move);
 }
示例#14
0
        public async Task <StatusCodeResult> Post()
        {
            DialogueFrame df;
            string        body;

            using (var reader = new StreamReader(Request.Body))
                body = await reader.ReadToEndAsync();

            var update = JsonConvert.DeserializeObject <Update>(body);

            if (update.Type != Telegram.Bot.Types.Enums.UpdateType.Message)
            {
                return(Ok());
            }

            Console.WriteLine(update);

            using (var ctx = new HealthBotContext())
            {
                var tlgrmUser = update.Message.From;
                var dbUser    = ctx.users.Where(t => t.loginTelegram == tlgrmUser.Username).FirstOrDefault();

                if (dbUser == null) //если пользователя нет
                {
                    dbUser = new users()
                    {
                        loginTelegram    = tlgrmUser.Username,
                        fio              = tlgrmUser.FirstName + " " + tlgrmUser.LastName,
                        telegram_chat_id = update.Message.Chat.Id
                    };
                    ctx.users.Add(dbUser);
                }

                //обработка сообщения (Dialogue state tracker)
                df = DialogueFrame.GetDialogueFrame(update, ctx, dbUser);

                //внутренняя работа в рамках платформы
                if (df.Activity == DialogueFrame.EnumActivity.DoNothing)
                {
                    return(Ok());
                }
                switch (df.Activity)
                {
                case DialogueFrame.EnumActivity.Answer:
                    await ctx.questions_answers.AddAsync(new questions_answers
                    {
                        id_user     = dbUser.id,
                        id_question = dbUser.id_last_question.Value,
                        value       = df.Entity,
                        date_time   = DateTime.Now
                    });

                    break;

                case DialogueFrame.EnumActivity.SystemAnswer:
                    break;

                case DialogueFrame.EnumActivity.LoadFile:
                    var path = Path.GetFullPath(@"..\..\");
                    var name = update.Message.Photo[update.Message.Photo.Length - 1].FileId;
                    DownloadFile(name, path + name);
                    ctx.files.Add(new files
                    {
                        content_hash = name,
                        directory    = "test",
                        id_user      = dbUser.id,
                        file_name    = name,
                        file_format  = "jpg",
                        id_source    = 1
                    });
                    break;

                case DialogueFrame.EnumActivity.ReadMyBiomarkers:
                    dbUser.id_last_question        = null;
                    dbUser.is_last_question_system = false;
                    break;

                case DialogueFrame.EnumActivity.ConversationStart: break;

                case DialogueFrame.EnumActivity.Unknown: break;
                }

                //обработка следующего сообщения (Dialogue state manager)
                await DialogueFrame.SendNextMessage(df, ctx, dbUser, update.Message.Chat, Bots.telegramBot);

                await ctx.SaveChangesAsync();
            }

            return(Ok());
        }
示例#15
0
        private static async void ProcessMessage(User tlgrmUser, Message message)
        {
            DialogueFrame df;

            using (var ctx = new HealthBotContext())
            {
                var dbUser = ctx.users.Where(t => t.loginTelegram == tlgrmUser.Username).FirstOrDefault();

                if (dbUser == null) //если пользователя нет
                {
                    dbUser = new users()
                    {
                        loginTelegram    = tlgrmUser.Username,
                        fio              = tlgrmUser.FirstName + " " + tlgrmUser.LastName,
                        telegram_chat_id = message.Chat.Id
                    };
                    ctx.users.Add(dbUser);
                }

                //обработка сообщения (Dialogue state tracker)
                df = DialogueFrame.GetDialogueFrame(message, ctx, dbUser);

                //внутренняя работа в рамках платформы
                if (df.Activity == DialogueFrame.EnumActivity.DoNothing)
                {
                    return;
                }
                switch (df.Activity)
                {
                case DialogueFrame.EnumActivity.Answer:
                    await ctx.questions_answers.AddAsync(new questions_answers
                    {
                        id_user     = dbUser.id,
                        id_question = dbUser.id_last_question.Value,
                        value       = df.Entity,
                        date_time   = DateTime.Now
                    });

                    break;

                case DialogueFrame.EnumActivity.SystemAnswer:
                    break;

                case DialogueFrame.EnumActivity.LoadFile:
                    var path = Path.GetFullPath(@"..\..\");
                    var name = message.Photo[message.Photo.Length - 1].FileId;
                    DownloadFile(name, path + name);
                    ctx.files.Add(new files
                    {
                        content_hash = name,
                        directory    = "test",
                        id_user      = dbUser.id,
                        file_name    = name,
                        file_format  = "jpg",
                        id_source    = 1
                    });
                    break;

                case DialogueFrame.EnumActivity.ReadMyBiomarkers:
                    dbUser.id_last_question        = null;
                    dbUser.is_last_question_system = false;
                    break;

                case DialogueFrame.EnumActivity.ConversationStart: break;

                case DialogueFrame.EnumActivity.Unknown: break;
                }

                //обработка следующего сообщения (Dialogue state manager)
                await DialogueFrame.SendNextMessage(df, ctx, dbUser, message.Chat, Shared.telegramBot);

                await ctx.SaveChangesAsync();
            }
        }
 void Start()
 {
     dialogueFrame = GetComponentInParent <DialogueFrame>();
     StartCoroutine(AnimateArrow());
 }
示例#17
0
 public void BeginDialogue(string firstFrameID)
 {
     inDialogue  = true;
     curDialogue = frameMap [firstFrameID];
     //frameMap [firstFrameID];
 }
示例#18
0
        public async Task <StatusCodeResult> Post()
        {
            DialogueFrame df;

            if (callbackData.Event != EventType.Message)
            {
                return(Ok());
            }

            using (var ctx = new HealthBotContext())
            {
                var viberUser = callbackData.Sender;
                var dbUser    = ctx.users.Where(t => t.loginViber == viberUser.Id).FirstOrDefault(); //изменить БД
                if (AppInfo.isDebugging)
                {
                    Console.WriteLine("В БД ЗАШЛО");
                }

                if (dbUser == null) //если пользователя нет
                {
                    if (AppInfo.isDebugging)
                    {
                        Console.WriteLine("ДОБАВЛЯЮ ПОЛЬЗОВАТЕЛЯ В БД");
                    }
                    dbUser = new users()
                    {
                        loginViber = viberUser.Id,
                        fio        = viberUser.Name
                    };
                    ctx.users.Add(dbUser);
                }
                //обработка сообщения (Dialogue state tracker)
                df = DialogueFrame.GetDialogueFrame(callbackData, ctx, dbUser);
                if (AppInfo.isDebugging)
                {
                    Console.WriteLine("СООБЩЕНИЕ ПОНЯТНО");
                }

                if (df.Activity == DialogueFrame.EnumActivity.DoNothing)
                {
                    return(Ok());
                }
                switch (df.Activity)
                {
                case DialogueFrame.EnumActivity.Answer:
                    await ctx.questions_answers.AddAsync(new questions_answers
                    {
                        id_user     = dbUser.id,
                        id_question = dbUser.id_last_question.Value,
                        value       = df.Entity,
                        date_time   = DateTime.Now
                    });

                    break;

                case DialogueFrame.EnumActivity.SystemAnswer:
                    break;

                case DialogueFrame.EnumActivity.LoadFile:
                    if (AppInfo.isDebugging)
                    {
                        Console.WriteLine("EnumActivity.LoadFile");
                    }
                    {
                        var path = Path.GetFullPath(@"..\");
                        if (AppInfo.isDebugging)
                        {
                            Console.WriteLine("ПУТЬ: " + path);
                        }
                        var uri  = ((PictureMessage)callbackData.Message).Media;
                        var name = uri.Substring(uri.LastIndexOf('/') + 1, uri.LastIndexOf('.') - uri.LastIndexOf('/') - 1);
                        if (AppInfo.isDebugging)
                        {
                            Console.WriteLine("ИМЯ: " + name);
                        }

                        using (var client = new WebClient())
                        {
                            client.DownloadFile(uri, path + name);
                        }

                        ctx.files.Add(new files
                        {
                            content_hash = name,
                            directory    = "test",
                            id_user      = dbUser.id,
                            file_name    = name,
                            file_format  = "jpg",
                            id_source    = 2
                        });
                        await ctx.SaveChangesAsync();

                        await Bots.viberBot.SendTextMessageAsync(new TextMessage()
                        {
                            Text   = "Изображение сохранено",
                            Sender = new UserBase()
                            {
                                Avatar = "https://dl-media.viber.com/1/share/2/long/vibes/icon/image/0x0/3eb4/af60406bde950b540663e6cad3f92ed79970d0ca6a6291491da8b00c3f643eb4.jpg",
                                Name   = "HealhBot"
                            },
                            Receiver      = callbackData.Sender.Id,
                            MinApiVersion = callbackData.Message.MinApiVersion,
                            TrackingData  = callbackData.Message.TrackingData
                        });

                        break;
                    }
                    break;

                case DialogueFrame.EnumActivity.ReadMyBiomarkers:
                    dbUser.id_last_question        = null;
                    dbUser.is_last_question_system = false;
                    break;

                case DialogueFrame.EnumActivity.ConversationStart: break;

                case DialogueFrame.EnumActivity.Unknown: break;
                }

                //обработка следующего сообщения (Dialogue state manager)
                DialogueFrame.SendNextMessage(df, ctx, dbUser, callbackData, Bots.viberBot);
                await ctx.SaveChangesAsync();
            }
            return(Ok());
        }
示例#19
0
    // ********************************************************************


    // ********************************************************************
        #if UNITY_EDITOR
    // ********************************************************************
    public void DrawUI()
    {
        SerializedObject serialized = new SerializedObject(this);

        serialized.Update();
        string oldID = id;

        Rect outerRect = EditorGUILayout.BeginVertical("Box");

        EditorGUI.DrawRect(outerRect, character == null ? Color.white : character.editorColor);
        // create delete button for child
        {
            GUIStyle style = new GUIStyle();
            style.alignment = TextAnchor.MiddleRight;
            EditorGUILayout.BeginHorizontal(style);
            if (GUILayout.Button(expanded ? "-" : "+", GUILayout.Width(25)))
            {
                expanded = !expanded;
            }
            EditorGUILayout.LabelField(id, EditorStyles.boldLabel);
            GUILayout.FlexibleSpace();
            Color oldColor = GUI.backgroundColor;
            GUI.backgroundColor = Color.green;
            if (GUILayout.Button("+", GUILayout.Width(25)))
            {
                conversation.AddNewFrameAt(conversation.frames.IndexOf(this) + 1);
            }
            if (GUILayout.Button("=", GUILayout.Width(25)))
            {
                DialogueFrame newFrame = CreateInstance <DialogueFrame>();
                EditorUtility.CopySerialized(this, newFrame);
                conversation.AddFrameAt(newFrame, conversation.frames.IndexOf(this) + 1);
            }
            GUI.backgroundColor = oldColor;
            if (GUILayout.Button("/\\", GUILayout.Width(25)))
            {
                conversation.MoveFrame(this, -1);
            }
            if (GUILayout.Button("\\/", GUILayout.Width(25)))
            {
                conversation.MoveFrame(this, +1);
            }
            if (GUILayout.Button("/|\\", GUILayout.Width(25)))
            {
                conversation.MoveFrameTo(this, 0);
            }
            if (GUILayout.Button("\\|/", GUILayout.Width(25)))
            {
                conversation.MoveFrameTo(this, conversation.frames.Count - 1);
            }
            GUI.backgroundColor = Color.red;
            if (GUILayout.Button("X", GUILayout.Width(25)))
            {
                conversation.RemoveFrame(this);
                return;
            }
            GUI.backgroundColor = oldColor;
            EditorGUILayout.EndHorizontal();
        }
        ++EditorGUI.indentLevel;
        if (expanded)
        {
            SerializedProperty property = serialized.GetIterator();
            property.NextVisible(true);
            do
            {
                EditorGUILayout.PropertyField(property, !property.hasVisibleChildren || property.isExpanded);
            } while (property.NextVisible(false));
        }
        --EditorGUI.indentLevel;
        EditorGUILayout.EndVertical();

        serialized.ApplyModifiedProperties();

        // If id changed, change file name
        if (id != oldID)
        {
            string originalName      = AssetDatabase.GetAssetPath(this);
            string parentFolder      = Path.GetDirectoryName(originalName);
            string newName           = "DF-" + id;
            string newNamePath       = parentFolder + "/" + newName + ".asset";
            string uniqueNewNamePath = AssetDatabase.GenerateUniqueAssetPath(newNamePath);
            string uniqueNewName     = Path.GetFileNameWithoutExtension(uniqueNewNamePath);
            if (uniqueNewName != originalName)
            {
                string result = AssetDatabase.RenameAsset(originalName, uniqueNewName);
                if (!result.NullOrEmpty())
                {
                    Debug.LogError("Error renaming asset: " + result);
                }
                AssetDatabase.SaveAssets();
                AssetDatabase.Refresh();
            }
        }
    }