[Unity] 커스텀 에디터 _Custom Editor - effect prefab name to data sheet(export .csv)

2019. 7. 24. 16:16unity/unity script

the programmer is an expert in making program and code base system
but they don't know exactly about what we want 

because they are a programmer and we are an art designer.

 

sometimes request to me about

 

"why we write exlex sheet? it's very hard work !!

"we don't have time very busy .. can you make some... tools for us to save our time"

 

But the general programmer in a team project doesn't respond to that request.

 

that is simple exel exporter(code)

//

first serch on google...

find solution

ctr+c > ctr+v

finish

//

 

// it was base on sprite maker script(not update yet)

 

 

///// full code - code detail explanation  is under this code

 

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using System.IO;
using System;
using System.Text;

public class CreateEffectSheet : EditorWindow
{
    static CreateEffectSheet myWindow;
    UnityEngine.Object targetObj;

    private List<string[]> rowData = new List<string[]>();

    int SheetIndex;
    string secondtext = "";
    string rotationtext = "";
    bool issavedata = true;
    StreamWriter outStream;


    string[] fileTypeNames = { "폴더", "더미생성" };
    int fileType = 0;

   
    string[] guids;

    [MenuItem("Window/CreateEffectSheet")]

    static void Init()
    {
        // Get existing open window or if none, make a new one:
        myWindow = (CreateEffectSheet)GetWindow(typeof(CreateEffectSheet));
        myWindow.Show();
    }

    private void OnDestroy()    {
        CloseSpriteViewerWindow();
    }

    void CloseSpriteViewerWindow()    {
        Reset();
    }

    void Reset() { 
        targetObj = null;
    }



    void OnGUI()
    {
        int type = EditorGUILayout.Popup(fileType, fileTypeNames, GUILayout.Height(20));
        if (fileType != type)
        {
            CloseSpriteViewerWindow();
            fileType = type;
            Reset();
        }

        if (fileType == 0)
        {
            var obj = EditorGUILayout.ObjectField("프리팹폴더 :", targetObj, typeof(DefaultAsset), true);
            if (targetObj != obj)
            {
                targetObj = obj;
            }
            else
            {
                if (targetObj != null)
                {
                    if (GUILayout.Button("시트 작성", GUILayout.Height(80)))
                    {
                        SheetIndex = -1;
                        secondtext = "";
                        rotationtext = "";
                        rowData.Clear();
                        Save();
                    }
                }

            }
        }
        
    }
    void Save()
    {

        // Creating First row of titles manually..
        string[] rowDataTemp = new string[3];
        rowDataTemp[0] = "No";
        rowDataTemp[1] = "Name";
        rowDataTemp[2] = "rotation";
        rowData.Add(rowDataTemp);
        //make list length & name value

        var tempPath = AssetDatabase.GetAssetPath(targetObj);
        string[] guids = AssetDatabase.FindAssets("t:Prefab", new string[] { tempPath });


        // 리스트 작성 프리팹 갯수만큼 정리
        int sheetlength = guids.Length;

        for (int i = 0; i < guids.Length; ++i)
        {
            string path = AssetDatabase.GUIDToAssetPath(guids[i]);

            //get prefab name
            string[] tempsprit = path.Split('/');
            var lastindex = tempsprit.Length;
 Debug.Log("sheet length::" + sheetlength);
            string newname = tempsprit[lastindex - 1];

            //break prefab name 
            string[] breakname = newname.Split('_');
            string LastBreakstring = breakname[breakname.Length - 1];
Debug.Log("lastbrekindex :: " + LastBreakstring);

            //remove .prefab
            string lastnumber = LastBreakstring.Replace(".prefab", "");
            //lastnumber 조건에 따라 저장하거나 건너뛴다
                if (lastnumber == "0")
                {
                    SheetIndex = ++SheetIndex;
                    rotationtext = "0";
                Debug.Log("index:: " + SheetIndex);
            }
                else if (lastnumber == "360")
                {
                    SheetIndex = ++SheetIndex;
                    rotationtext = "1";
                }
                else if (lastnumber == "720")
                {
                    SheetIndex = ++SheetIndex;
                    rotationtext = "2";
                }
                else
                {
                    issavedata = false;
                }

            string tempindex = SheetIndex.ToString("D3");//3자리로 자릿수를 맞춘다
            //append name excute last number
            secondtext = newname.Replace("_" + LastBreakstring, "");


            Debug.Log("index:: " + tempindex);

            rowDataTemp = new string[3];
            rowDataTemp[0] = tempindex; // number
            rowDataTemp[1] = secondtext; // name
            rowDataTemp[2] = rotationtext; // rotation

            if (issavedata == true)
                rowData.Add(rowDataTemp);
            else
                issavedata = true;
        }


        string[][] output = new string[rowData.Count][];

        for (int i = 0; i < output.Length; i++)
        {
            output[i] = rowData[i];
        }

        int length = output.GetLength(0);
        string delimiter = ",";

        StringBuilder sb = new StringBuilder();

        for (int index = 0; index < length; index++)
            sb.AppendLine(string.Join(delimiter, output[index]));


        string filePath = GetPath();

        outStream = System.IO.File.CreateText(filePath);

        StringBuilder sbtemp = new StringBuilder();
        sbtemp.AppendLine("");
        outStream.WriteLine(sbtemp);

        outStream.WriteLine(sb);
        outStream.Close();

        issavedata = true;

        AssetDatabase.Refresh();
    }
    // Following method is used to retrive the relative path as device platform
    private string GetPath()
    {
#if UNITY_EDITOR
        return Application.dataPath + "/" + "Saved_data.csv";
#elif UNITY_ANDROID
        return Application.persistentDataPath+"Saved_data.csv";
#elif UNITY_IPHONE
        return Application.persistentDataPath+"/"+"Saved_data.csv";
#else
        return Application.dataPath +"/"+"Saved_data.csv";
#endif
    }
}

 

//////////////////////////////////////////////////////////////

 

code detail explanation 

 

 

public class CreateEffectSheet : EditorWindow << decalre we use unity editor window
{ 
    static CreateEffectSheet myWindow; 
    UnityEngine.Object targetObj; << this line used in "find target foler"

    private List<string[]> rowData = new List<string[]>(); << row data is used in "creat date sheet"

    int SheetIndex; 
    string secondtext = ""; 
    string rotationtext = ""; 
    bool issavedata = true; 
    StreamWriter outStream; 


    string[] fileTypeNames = { "폴더", "더미생성" }; 
    int fileType = 0; 

    
    string[] guids; 

    [MenuItem("Window/CreateEffectSheet")] << create menu item in unity editor

    static void Init() 
    { 
        // Get existing open window or if none, make a new one: 
        myWindow = (CreateEffectSheet)GetWindow(typeof(CreateEffectSheet)); <<inity offical tutorial
        myWindow.Show(); 
    } 

    private void OnDestroy()    { 
        CloseSpriteViewerWindow(); 
    } 

    void CloseSpriteViewerWindow()    { 
        Reset(); 
    } 

    void Reset() {  
        targetObj = null; 
    } 

<<createeffectsheet window



    void OnGUI() <<offical tutorial ongui is use customeditor 
    { 
        int type = EditorGUILayout.Popup(fileType, fileTypeNames, GUILayout.Height(20)); 

<< select popup it was select format but not used in this script

        if (fileType != type) 
        { 
            CloseSpriteViewerWindow(); 
            fileType = type; 
            Reset(); 
        } 

<<If the Type does not match, this script will not work.

        if (fileType == 0) 
        { 
            var obj = EditorGUILayout.ObjectField("프리팹폴더 :", targetObj, typeof(DefaultAsset), true); 
            if (targetObj != obj) 
            { 
                targetObj = obj; 
            } 
            else 
            { 
                if (targetObj != null) 
                { 

 

<< Filters the condition and creates a button"create sheet" if all conditions are true.
                    if (GUILayout.Button("시트 작성", GUILayout.Height(80))) 
                    { 
                        SheetIndex = -1; 
                        secondtext = ""; 
                        rotationtext = ""; 
                        rowData.Clear(); 

<<reset all variable
                        Save(); << it is main code create sheet
                    } 
                } 

            } 
        } 
         
    } 

 

<// my code is so dirty but it is just in the subtask, once again say "I'm not a programmer"
    void Save() 
    { 

created csv file


        // Creating First row of titles manually.. 
        string[] rowDataTemp = new string[3]; 

<// it is static row, if you wnat more colum, you write onother nomber// new string[10]
        rowDataTemp[0] = "No"; 
        rowDataTemp[1] = "Name"; 
        rowDataTemp[2] = "rotation"; 
        rowData.Add(rowDataTemp); 
        //make list length & name value 

        var tempPath = AssetDatabase.GetAssetPath(targetObj); 
        string[] guids = AssetDatabase.FindAssets("t:Prefab", new string[] { tempPath }); 
<//get filepath about selected folder 

<// Check the prefab objects in the folder tree and put them into an array"guid[]"


        // 리스트 작성 프리팹 갯수만큼 정리 
        int sheetlength = guids.Length; 
        for (int i = 0; i < guids.Length; ++i) 


        { 
            string path = AssetDatabase.GUIDToAssetPath(guids[i]); 

            //get prefab name 
            string[] tempsprit = path.Split('/'); 
            var lastindex = tempsprit.Length; 

            string newname = tempsprit[lastindex - 1]; 


<//get prefab name

<//guids[i] = ex)D:/work/art_testPJ/Assets/fx_bst_mg_pj_360.prefab

<//string[] = splite by / >

string[0] = d

string[1] = work

..

string[4] = fx_bst_mg_pj_360.prefab

 

check index's length  (on example is 5) index length -1 is the last index>> string[last index]  become file name


            //break prefab name  
            string[] breakname = newname.Split('_'); 
            string LastBreakstring = breakname[breakname.Length - 1]; 


            //remove .prefab 
            string lastnumber = LastBreakstring.Replace(".prefab", ""); 

<//split again by "." >> replace .prefab to void("") it is same acrtion as remove string


            //lastnumber 조건에 따라 저장하거나 건너뛴다 
                if (lastnumber == "0") 
                { 
                    SheetIndex = ++SheetIndex; 
                    rotationtext = "0"; 
                Debug.Log("index:: " + SheetIndex); 
            } 
                else if (lastnumber == "360") 
                { 
                    SheetIndex = ++SheetIndex; 
                    rotationtext = "1"; 
                } 
                else if (lastnumber == "720") 
                { 
                    SheetIndex = ++SheetIndex; 
                    rotationtext = "2"; 
                } 
                else 
                { 
                    issavedata = false; 
                } 
<//set variables from current condition

<// Our team has defined file name rules in advance.

<// end text 0 = rotated = 0, 360 = not rotated = 1, 720 = all rotated = 2

<// 
            string tempindex = SheetIndex.ToString("D3");//3자리로 자릿수를 맞춘다 
            //append name excute last number 
            secondtext = newname.Replace("_" + LastBreakstring, ""); 

 

<// get completed  this turn's variable's value (sheetindex, secondtext, rotation)

value// write code block's content depend on your team's rules and have to get the correct value

 

           rowDataTemp = new string[3]; 
            rowDataTemp[0] = tempindex; // number 
            rowDataTemp[1] = secondtext; // name 
            rowDataTemp[2] = rotationtext; // rotation 

            if (issavedata == true) <// if file end text is 0, 360, 720 > save other > not save
                rowData.Add(rowDataTemp); 
            else 
                issavedata = true; 
        } 

<// code under this line is copy from google.com

<// craft data table use 2-dimensional array


        string[][] output = new string[rowData.Count][]; 

        for (int i = 0; i < output.Length; i++) 
        { 
            output[i] = rowData[i]; 
        } 

        int length = output.GetLength(0); 
        string delimiter = ","; 

        StringBuilder sb = new StringBuilder(); 

        for (int index = 0; index < length; index++) 
            sb.AppendLine(string.Join(delimiter, output[index])); 


        string filePath = GetPath(); 

        outStream = System.IO.File.CreateText(filePath); 


<// create csv file using systme.stringbuilder and rowdata

<// rowdata.count is number of line


        StringBuilder sbtemp = new StringBuilder(); 
        sbtemp.AppendLine(""); 
        outStream.WriteLine(sbtemp); 

        outStream.WriteLine(sb); 
        outStream.Close(); 

        issavedata = true; 

        AssetDatabase.Refresh(); 
    } 
    // Following method is used to retrive the relative path as device platform 
    private string GetPath() 
    { 
#if UNITY_EDITOR 
        return Application.dataPath + "/" + "Saved_data.csv"; 
#else 
        return Application.dataPath +"/"+"Saved_data.csv"; 
#endif 
    } 
}