Créer ScriptableObject en Python lors de la construction d'ADX2

introduction

Dans Unity à la fois dans l'éditeur et au moment de l'exécution Je voulais accéder à diverses informations sur ADX2.

Cet article est probablement un peu plus difficile (manque d'explication).

S'il ne s'agit que du nom de la file d'attente, l'article précédent Introduction de scripts utiles tels que la copie vers Unity lors de la construction d'ADX2 Veuillez aussi.

le terme

À propos de ScriptableObject

Page de kan_kikuchi Qu'est-ce qu'un objet scriptable? [Unity] [Objet scriptable]

ADX2 Le middleware audio ADX2LE peut être utilisé gratuitement (des conditions s'appliquent)

ptyhon Ici

Information pour qui?

・ Les personnes qui veulent écrire du code qui génère ScriptableObject ・ Les personnes qui souhaitent utiliser la sortie xml d'ADX2 d'une manière ou d'une autre ・ Les personnes qui souhaitent analyser xml avec python et générer du code c #

Pourquoi avez-vous réussi?

Obtenez des informations un peu difficiles à récupérer avec la méthode standard ADX2

Il y a des informations qui peuvent être obtenues par la fonction Acb au moment de l'exécution, et via la sortie du fichier cs au moment de la construction. Je voulais gérer uniquement les informations nécessaires en un seul endroit.

Informations qui ne peuvent être obtenues directement

Je voulais extraire des informations qui pourraient être utilisées pour quelque chose.

("Quelque chose" ici peut être un outil interne.)

Que puis-je faire?

Après la construction avec ADX2 Lors de l'exécution à partir du menu sur Unity

image.png

Générez un fichier .assets qui ressemble à ceci. Il est fait autant que le nombre de feuilles de repères.

Facile à utiliser depuis le programme

Si vous faites référence à ce ScriptableObject généré à partir de l'objet Unity, vous pouvez gérer les informations ACB d'ADX2 dans chaque situation. De plus, comme il est automatiquement mis à jour au moment de la construction (l'utilisation du menu est requise *), les erreurs de transmission d'informations peuvent être réduites.

("Chaque scène" fait ici référence au moment de l'exécution, de l'éditeur, de la construction, etc.)

Utilisation des commentaires

En outre, des commentaires et autres "commentaires" peuvent être ajoutés à chaque file d'attente pour ceux qui ne touchent qu'avec Unity. Vous pouvez le voir dans l'extension de l'éditeur, il semble donc bon d'utiliser divers commentaires

Par exemple, "Données temporaires" ou "Date de mise à jour" (ADX2-> Commentaire unilatéral vers Unity, donc ce n'est pas bidirectionnel ...)

Analyser xml avec python

Utilisez python pour analyser xml. Sélectionnez les informations nécessaires avec python et Générez le code qui crée le ScriptableObject.

À propos de l'AISAC

J'aimerais connaître le nom du contrôle AISAC, mais lorsque je fais référence à l'AISAC global, il n'est pas généré en XML, Comme convention de dénomination Nom @ nom du contrôle Adopté

image.png

Paramètres de construction ADX2 dans AtomCraft

--Vérifiez la sortie XML "acb_info"

Appel de python en post-processus (Les noms de fichiers sont légèrement différents ici, mais ils sont appelés de la même manière.)

image.png

Classe ScriptableObject

Si vous ajoutez les informations nécessaires, il devrait être pratique d'utiliser les informations de XML dans Unity.

 ADXAcbData.cs


using System;
using System.Collections.Generic;
using UnityEngine;

namespace MyDearest {
	[CreateAssetMenu (menuName = "Sound/ADX Acb Data")]
	public class ADXAcbData
		: ScriptableObject
	{
		[Serializable]
		public class CueData {
			public string Name = "";
			public List<string> BlockNames = new List<string> ();
			public List<string> AisacNames = new List<string> ();
			public string Comment = "";
			public string UserData = "";
		}
		public string Name = "";
		public List<CueData> Cues = new List<CueData> ();

		private List<string> _cueNames = new List<string> ();
		/// <summary>
		///Renvoie une liste de noms de files d'attente
		/// </summary>
		/// <returns></returns>
		public string[] CueNames () {
			if (_cueNames.Count > 0) return _cueNames.ToArray ();
			foreach (CueData cuedata in Cues) {
				_cueNames.Add (cuedata.Name);
			}
			return _cueNames.ToArray ();
		}
	}
}

Code qui crée un ScriptableObject

Puisqu'il sera plus long du nombre de données, une seule file d'attente est omise ici.

AcbDataCreators.cs


using UnityEngine;
using UnityEditor;
namespace MyDearest {
	public static class AcbDataCreator {
		[MenuItem ("Sound/CreateAcbData")]
		private static void Create () {
			{
				ADXAcbData acb = ScriptableObject.CreateInstance<ADXAcbData> ();
				acb.Name = "BGM";
				{
					ADXAcbData.CueData cueData = new ADXAcbData.CueData ();
					cueData.Name = "Chronos";
					acb.Cues.Add (cueData);
				}
				AssetDatabase.CreateAsset (acb, "Assets/MyDearest/Chronos/Data/Sound/BGM.asset");
			}
		}
	}
}

Générer un fichier Unity CS avec python

Comment créer un ScriptableObject pour Unity

J'aimerais pouvoir créer un ScriptableObject directement à partir de python, mais je ne connaissais pas un peu les informations YAML d'Unity, donc Je crée le code source du menu pour créer ScriptObject avec unité.

C'est un peu difficile à voir car le code est généré en même temps que l'analyse, mais je me demande s'il est facile de comprendre ce que vous faites.

Veuillez corriger le nom du chemin comme il convient.

adx2xml_to_str_cs.py


#print("Créer ScriptableObject à partir de la sortie xml ADX2 C#Générer du code")

import xml.etree.ElementTree as ET
import os

g_currentCueName = ""  #Nom de la file d'attente
g_currentCueSheetName = "" #Nom de la feuille de file d'attente


def writeHeader(outstr):
    outstr += "using UnityEngine;\n"
    outstr += "using UnityEditor;\n"
    outstr += "namespace MyDearest {\n"
    outstr += "	public static class AcbDataCreator {\n"
    outstr += "		[MenuItem (\"Window/MDSound/CreateAcbData\")]\n"
    outstr += "		private static void Create () {\n"

    return outstr

def writeFooter(assetoutpath,outstr):
    outstr += "\t\t\t\t\tacb.Cues.Add (cueData);\n"
    outstr += "\t\t\t\t}\n"
    outstr += "\t\t\t\tEditorUtility.SetDirty (acb);\n"
    outstr += "\t\t\t}\n"
    outstr += "\t\t}\n"
    outstr += "\t}\n"
    outstr += "}\n"

    return outstr
        
def printOrcaName(nest,child,xmlpath,outpath,assetoutpath,outstr):
    global g_currentCueName,g_currentCueSheetName
    nestspacestr = ""
    for i in range(nest):
        nestspacestr +=" "
    
    if(child.get("OrcaType") == "CriMw.CriAtomCraft.AcCore.AcOoCueSheet"):        
        print("Nom de la feuille de file d'attente" + child.get("OrcaName"))   #Feuille de repère

        if(g_currentCueSheetName != "" and g_currentCueSheetName != child.get("OrcaName")):   #Seulement lorsque la feuille de repère change
            outstr += "\t\t\t\t\tacb.Cues.Add (cueData);\n"
            outstr += "\t\t\t\t}\n"
            outstr += "\t\t\t\tEditorUtility.SetDirty (acb);\n"
            outstr += "\t\t\t}\n"


        g_currentCueSheetName = child.get("OrcaName")
        g_currentCueName = ""
        outstr += "\t\t\t{\n"        
        outstr += "\t\t\t\tADXAcbData acb = (ADXAcbData)AssetDatabase.LoadAssetAtPath (\"" + assetoutpath + g_currentCueSheetName + ".asset\", typeof (ADXAcbData));\n"
        outstr += "\t\t\t\tif (acb == null) {\n"
        outstr += "\t\t\t\t        acb = ScriptableObject.CreateInstance<ADXAcbData> ();	//Faire quand non\n"
        outstr += "\t\t\t\t        AssetDatabase.CreateAsset (acb, \"" + assetoutpath + g_currentCueSheetName + ".asset\");\n"
        outstr += "\t\t\t\t        acb = (ADXAcbData)AssetDatabase.LoadAssetAtPath (\"" + assetoutpath + g_currentCueSheetName + ".asset\", typeof (ADXAcbData));\n"
        outstr += "\t\t\t\t}\n"
        outstr += "\t\t\t\tacb.Cues.Clear ();\n"
        outstr += "\t\t\t\tacb.Name = \"" + g_currentCueSheetName + "\";\n"
    if(child.get("OrcaType") == "CriMw.CriAtomCraft.AcCore.AcOoCueFolder"):
        print(nestspacestr + "Nom du dossier de la file d'attente" + child.get("OrcaName"))
    if(child.get("OrcaType") == "CriMw.CriAtomCraft.AcCore.AcOoCueSynthCue"): #queue
        print(nestspacestr + "Nom de la file d'attente" + child.get("OrcaName"))

        if(g_currentCueName != "" and g_currentCueName != child.get("OrcaName")):   #Fermer lorsque la file d'attente change
            outstr += "					acb.Cues.Add (cueData);\n"
            outstr += "				}\n"

        g_currentCueName = child.get("OrcaName")
        outstr += "				{\n"
        outstr += "					ADXAcbData.CueData cueData = new ADXAcbData.CueData ();\n"
        outstr += "					cueData.Name = \"" + g_currentCueName + "\";\n"
        
        if 'UserData' in child.attrib:
            outstr += "					cueData.UserData = @\"" + child.get("UserData") + "\";\n"
        if 'Comment' in child.attrib:
            outstr += "					cueData.Comment = @\"" + child.get("Comment") + "\";\n"
            
    if(child.get("OrcaType") == "CriMw.CriAtomCraft.AcCore.AcOoAisac"):
        print(nestspacestr + "Nom du contrôle AISAC" + os.path.basename(child.get("AisacControl")))
        outstr += "					cueData.AisacNames.Add (\"" + os.path.basename(child.get("AisacControl")) + "\");\n"
    if(child.get("OrcaType") == "CriMw.CriAtomCraft.AcCore.AcOoAisacLink"):
        print(nestspacestr + "Nom du contrôle AISAC" + os.path.basename(child.get("LinkAisac")).split('@')[1])  # Distance@Avec une convention de dénomination comme Distance@Derrière le nom du contrôle((Parce que LinkAisac n'a pas AisacControl)
        outstr += "					cueData.AisacNames.Add (\"" + os.path.basename(child.get("LinkAisac")).split('@')[1] + "\");\n"
    if(child.get("OrcaType") == "CriMw.CriAtomCraft.AcCore.AcOoBlock"):
        print(nestspacestr + "Nom du bloc" + child.get("OrcaName"))
        outstr += "					cueData.BlockNames.Add (\"" + child.get("OrcaName") + "\");\n"

    return outstr

#Générer du code de génération d'objets scriptable en analysant XML
def conv(xmlpaths,outpath,assetoutpath):
    outstr = "";    
    outstr = writeHeader(outstr)

    for xmlpath in xmlpaths:
        tree = ET.parse(xmlpath) 
        root = tree.getroot()
        for child in root:
            for child1 in child:
                for child2 in child1:
                    for child3 in child2:
                        outstr = printOrcaName(0,child3,xmlpath,outpath,assetoutpath,outstr)
                        for child4 in child3:
                            outstr = printOrcaName(1,child4,xmlpath,outpath,assetoutpath,outstr)
                            for child5 in child4:
                                outstr = printOrcaName(2,child5,xmlpath,outpath,assetoutpath,outstr)
                                for child6 in child5:
                                    outstr = printOrcaName(3,child6,xmlpath,outpath,assetoutpath,outstr)
                                    for child7 in child6:
                                        outstr = printOrcaName(4,child7,xmlpath,outpath,assetoutpath,outstr)


    outstr = writeFooter(assetoutpath,outstr)
    
    print(outstr)
    with open(outpath,"w",encoding="utf-8") as f:
        f.write(outstr)

#Destination de sortie de construction (pas de sortie en couches)
adx2outputpath = "C:/MyDearest/CraftData/OculusAdxTest/PC/"
#Liste XML à analyser
cuesheetXmlNames = [adx2outputpath + "BGM_acb_info.xml",
                 adx2outputpath + "SE_acb_info.xml",
                 adx2outputpath + "VOICE_acb_info.xml"]

#Spécifiez l'emplacement de la conversion réelle et du fichier cs généré et l'emplacement des actifs générés par le fichier généré
conv(cuesheetXmlNames,
     "C:/MyDearest/github/Chronos/Assets/MyDearest/Sound/Editor/AcbDataCreator.cs",
     "Assets/MyDearest/Chronos/Data/Sound/")

Je suis désolé L'analyse récursive de xml est un code un peu décevant et désordonné, mais veuillez l'ajouter en fonction de la complexité des données.

en conclusion

Comme application Il est facile d'analyser le XML et de créer un fichier texte, donc Il peut également être utilisé à des fins de vérification, de gestion des versions et de coopération avec les outils ci.

Le code ici n'est pas pris en charge, mais par exemple

Je pense que je peux l'enlever. Cependant, si vous les supprimez tous aveuglément, ce sera énorme et difficile à gérer et les données seront gonflées. Je pense que c'est bien de ne pouvoir récupérer que les informations nécessaires.

Il peut être utilisé à l'avenir à des fins telles que le remplacement des données au moment de la construction ou la suppression des informations de débogage (bien que je ne l'ai pas encore essayé).

En outre, il peut être possible de télécharger des informations sur le cloud au moment de la construction, de rechercher des mises à jour à partir de là et de les générer automatiquement.

Recommended Posts

Créer ScriptableObject en Python lors de la construction d'ADX2
Créer Spatia Lite en Python
Créer une fonction en Python
Créer un dictionnaire en Python
Attention lorsque os.mkdir en Python
Précautions lors de l'utilisation de Pit avec Python
Créer un conteneur DI avec Python
Comportement lors de la liste dans Python heapq
Créer un fichier binaire en Python
Créez Gmail en Python sans utiliser l'API
Créer une documentation de projet Python dans Sphinx
Créer une chaîne aléatoire en Python
Lors de l'utilisation d'expressions régulières en Python
Lors de l'écriture d'un programme en Python
Créer et lire des paquets de messages en Python
Lors de la spécification de plusieurs clés dans le tri python
Créez vos propres commandes Linux en Python
Précautions lors du décapage d'une fonction en python
[LLDB] Créez votre propre commande avec Python
Créer une application GUI simple en Python
Créer des pièces de concepteur Qt avec Python (PyQt)
Lors de l'examen de l'utilisation de la mémoire dans Python 3
[GPS] Créer un fichier kml avec Python
[Astuces] Écriture facile à lire lors de la connexion de fonctions en Python
Quadtree en Python --2
Lorsque le codec ne peut pas décoder l'octet apparaît en python
Python en optimisation
Métaprogrammation avec Python
Créez un environnement de test Vim + Python en 1 minute
Python 3.3 avec Anaconda
Géocodage en python
SendKeys en Python
Créer un fichier GIF en utilisant Pillow en Python
Méta-analyse en Python
Créer un environnement qui utilise Python avec Eclipse
Unittest en Python
Je veux créer une fenêtre avec Python
Créer un graphique de distribution normale standard en Python
Quand j'essaye matplotlib en Python, il dit 'cairo.Context'
Comment créer un fichier JSON en Python
Créez automatiquement des rapports Word et Excel avec Python
Époque en Python
Créer un environnement virtuel avec conda avec Python
Discord en Python
Allemand en Python
DCI en Python
tri rapide en python
Précautions lors du traitement des structures de contrôle dans Python 2.6
nCr en python
N-Gram en Python
Remarque sur l'encodage lorsque LANG = C en Python
Programmation avec Python
Plink en Python
Constante en Python
Créer une image avec des caractères avec python (japonais)
Encodage de caractères lors du traitement de fichiers en Python 3
Pensez à créer un environnement Python 3 dans un environnement Mac