|
//Copyright( c) 2017 Andrew Carvalho, Laundry Bear Games Inc. |
|
|
|
//Permission is hereby granted, free of charge, to any person obtaining a copy |
|
//of this software and associated documentation files (the "Software"), to deal |
|
//in the Software without restriction, including without limitation the rights |
|
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
//copies of the Software, and to permit persons to whom the Software is |
|
//furnished to do so, subject to the following conditions: |
|
|
|
//The above copyright notice and this permission notice shall be included in all |
|
//copies or substantial portions of the Software. |
|
|
|
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
//SOFTWARE. |
|
|
|
using Microsoft.CSharp; |
|
using System; |
|
using System.CodeDom; |
|
using System.CodeDom.Compiler; |
|
using System.Collections.Generic; |
|
using System.IO; |
|
using System.Reflection; |
|
using UnityEditor; |
|
using UnityEngine; |
|
|
|
public class GenerateFmodGuids : Editor |
|
{ |
|
public class FmodConstant |
|
{ |
|
public enum ConstantType { Event, Bus, Bank } |
|
|
|
public ConstantType FmodType { get; private set; } |
|
public Guid Guid { get; private set; } |
|
public string Path { get; private set; } |
|
|
|
public FmodConstant( Guid guid, string path, ConstantType type ) |
|
{ |
|
Guid = guid; |
|
Path = path; |
|
FmodType = type; |
|
} |
|
|
|
public string GetParentPath() |
|
{ |
|
return Path.Substring( 0, Path.LastIndexOf( @"/" ) ); |
|
if ( Path.EndsWith( @"/" ) ) |
|
{ |
|
return Path.Substring( 0, Path.Length - 1 ); |
|
} |
|
return System.IO.Path.GetDirectoryName( Path ); |
|
} |
|
|
|
public string GetEventName() |
|
{ |
|
string eventName = System.IO.Path.GetFileName( Path ); |
|
// empty bus is valid and is a special case for the master bus |
|
if ( string.IsNullOrEmpty( eventName ) && FmodType == ConstantType.Bus ) |
|
{ |
|
eventName = "Master"; |
|
} |
|
return eventName; |
|
} |
|
|
|
} |
|
|
|
private const int GUID_INDEX = 0; |
|
private const int PATH_INDEX = 1; |
|
|
|
private const string FMOD_PATH_EVENT_KEY = "event"; |
|
private const string FMOD_PATH_BUS_KEY = "bus"; |
|
private const string FMOD_PATH_BANK_KEY = "bank"; |
|
|
|
[MenuItem( "Tools/Laundry Bear/Generate Fmod Events Constants File" )] |
|
public static void CreateEventsFile() |
|
{ |
|
string guidFilePath = AssetDatabase.GetAssetPath( Selection.activeObject.GetInstanceID() ); |
|
CreateLayersClass( guidFilePath ); |
|
} |
|
|
|
[MenuItem( "Tools/Laundry Bear/Generate Fmod Events Constants File", true )] |
|
public static bool ValidateCreateEventsFile() |
|
{ |
|
return Selection.activeObject is TextAsset; |
|
} |
|
|
|
private static FmodConstant[] GetConstantList( string path ) |
|
{ |
|
|
|
List<FmodConstant> guidPathList = new List<FmodConstant>(); |
|
|
|
using ( StreamReader reader = new StreamReader( path ) ) |
|
{ |
|
while ( !reader.EndOfStream ) |
|
{ |
|
string guidPath = reader.ReadLine(); |
|
string[] splitGuidPath = guidPath.Split( new char[] { ' ' }, 2 ); |
|
Guid guid = new Guid( splitGuidPath[ GUID_INDEX ] ); |
|
string guidTypeName = splitGuidPath[ PATH_INDEX ].Split( new char[] { ':' }, 2 )[0]; |
|
switch ( guidTypeName ) |
|
{ |
|
case FMOD_PATH_EVENT_KEY: |
|
guidPathList.Add( new FmodConstant( guid, splitGuidPath[PATH_INDEX].Trim(), FmodConstant.ConstantType.Event ) ); |
|
break; |
|
case FMOD_PATH_BUS_KEY: |
|
guidPathList.Add( new FmodConstant( guid, splitGuidPath[PATH_INDEX].Trim(), FmodConstant.ConstantType.Bus ) ); |
|
break; |
|
case FMOD_PATH_BANK_KEY: |
|
guidPathList.Add( new FmodConstant( guid, splitGuidPath[PATH_INDEX].Trim(), FmodConstant.ConstantType.Bank ) ); |
|
break; |
|
default: |
|
break; |
|
} |
|
} |
|
} |
|
|
|
return guidPathList.ToArray(); |
|
|
|
} |
|
|
|
static void CreateLayersClass( string path ) |
|
{ |
|
CodeCompileUnit codeCompileUnit = new CodeCompileUnit(); |
|
CodeNamespace codeNamespace = new CodeNamespace(); |
|
|
|
FmodConstant[] constants = GetConstantList( path ); |
|
|
|
// create classes for events, busses and banks |
|
CodeTypeDeclaration codeEventClass = CodeGeneration.CreateSealedPrivateClass( CodeGeneration.ConvertToValidIdentifier( "Events" ) ); |
|
CodeTypeDeclaration codeBusClass = CodeGeneration.CreateSealedPrivateClass( CodeGeneration.ConvertToValidIdentifier( "Busses" ) ); |
|
CodeTypeDeclaration codeBankClass = CodeGeneration.CreateSealedPrivateClass( CodeGeneration.ConvertToValidIdentifier( "Banks" ) ); |
|
|
|
// create a dictionary to hold all the class declarations |
|
Dictionary<string, CodeTypeDeclaration> classDictionary = new Dictionary<string, CodeTypeDeclaration>(); |
|
|
|
foreach ( FmodConstant constant in constants ) |
|
{ |
|
CodeTypeDeclaration codeClass = null; |
|
switch ( constant.FmodType ) |
|
{ |
|
case FmodConstant.ConstantType.Event: |
|
codeClass = codeEventClass; |
|
break; |
|
case FmodConstant.ConstantType.Bus: |
|
codeClass = codeBusClass; |
|
break; |
|
case FmodConstant.ConstantType.Bank: |
|
codeClass = codeBankClass; |
|
break; |
|
} |
|
|
|
if ( codeClass == null ) |
|
{ |
|
continue; |
|
} |
|
|
|
CodeTypeDeclaration containingClass = GetOrCreateClassDeclaration( constant.GetParentPath(), classDictionary, codeClass ); |
|
|
|
string backingGuidName = string.Format( "sm_{0}", constant.GetEventName() ); |
|
backingGuidName = CodeGeneration.ConvertToValidIdentifier( backingGuidName ); |
|
CodeMemberField codeGuidBackingFieldMember = CodeGeneration.CreatePrivateMember( typeof( Guid ), CodeGeneration.ConvertToValidIdentifier( backingGuidName ) ); |
|
codeGuidBackingFieldMember.Attributes &= ~MemberAttributes.AccessMask; |
|
codeGuidBackingFieldMember.Attributes &= ~MemberAttributes.ScopeMask; |
|
codeGuidBackingFieldMember.Attributes |= MemberAttributes.Private; |
|
codeGuidBackingFieldMember.Attributes |= MemberAttributes.Static; |
|
codeGuidBackingFieldMember.InitExpression = new CodeObjectCreateExpression( typeof( Guid ).FullName, new CodeExpression[] { new CodePrimitiveExpression( constant.Guid.ToString() ) } ); |
|
containingClass.Members.Add( codeGuidBackingFieldMember ); |
|
|
|
CodeMemberProperty codeGuidPropertyMember = CodeGeneration.CreateReadonlyPropertyMember( typeof ( Guid ), CodeGeneration.ConvertToValidIdentifier( constant.GetEventName() ) ); |
|
codeGuidPropertyMember.GetStatements.Add( new CodeMethodReturnStatement( new CodeFieldReferenceExpression() { FieldName = backingGuidName } ) ); |
|
containingClass.Members.Add( codeGuidPropertyMember ); |
|
|
|
CodeMemberField codePathMember = CodeGeneration.CreateConstMember( typeof ( string ), CodeGeneration.ConvertToValidIdentifier( string.Format( "{0}{1}", constant.GetEventName(), "Path" ) ) ); |
|
codePathMember.InitExpression = new CodePrimitiveExpression( constant.Path ); |
|
containingClass.Members.Add( codePathMember ); |
|
} |
|
|
|
CodeTypeDeclaration codeConstantsClass = CodeGeneration.CreateSealedPrivateClass( "FMODConstants" ); |
|
|
|
codeConstantsClass.Members.Add( codeEventClass ); |
|
codeConstantsClass.Members.Add( codeBusClass ); |
|
codeConstantsClass.Members.Add( codeBankClass ); |
|
|
|
codeNamespace.Types.Add( codeConstantsClass ); |
|
|
|
codeCompileUnit.Namespaces.Add( codeNamespace ); |
|
|
|
string outputPath = AssetDatabase.GetAssetPath(Selection.activeObject); |
|
outputPath = Path.GetDirectoryName( outputPath ) + "/FmodConstants.cs"; |
|
|
|
using ( var stream = new StreamWriter( outputPath, append: false ) ) |
|
{ |
|
var tw = new IndentedTextWriter(stream); |
|
var codeProvider = new CSharpCodeProvider(); |
|
codeProvider.GenerateCodeFromCompileUnit( codeCompileUnit, tw, new CodeGeneratorOptions() { BracingStyle = "C", BlankLinesBetweenMembers = false } ); |
|
} |
|
|
|
AssetDatabase.ImportAsset( path, ImportAssetOptions.ForceUpdate ); |
|
AssetDatabase.Refresh(); |
|
|
|
Debug.Log( "Completed FmodConstants.cs generation." ); |
|
} |
|
|
|
private static CodeTypeDeclaration GetOrCreateClassDeclaration( string path, Dictionary<string, CodeTypeDeclaration> classDictionary, CodeTypeDeclaration containingClass ) |
|
{ |
|
if ( path.IndexOf( @"/" ) < 0 ) |
|
{ |
|
return containingClass; |
|
} |
|
CodeTypeDeclaration classDeclaration; |
|
classDictionary.TryGetValue( path, out classDeclaration ); |
|
if ( classDeclaration == null ) |
|
{ |
|
string parentPath = path.Substring( 0, path.LastIndexOf(@"/") ); |
|
int start = path.LastIndexOf(@"/"); |
|
string localPath = path.Substring( start, path.Length - start ); |
|
classDeclaration = new CodeTypeDeclaration( CodeGeneration.ConvertToValidIdentifier( localPath ) ); |
|
// if this class has an encapsuating class |
|
if ( parentPath.IndexOf( @"/" ) > -1 ) |
|
{ |
|
// get encapsulating class |
|
CodeTypeDeclaration parentClassDeclaration = GetOrCreateClassDeclaration( parentPath, classDictionary, containingClass ); |
|
// add this class as a member |
|
parentClassDeclaration.Members.Add( classDeclaration ); |
|
} |
|
else |
|
{ |
|
// no encapsulating class, add it to the containing class argument |
|
containingClass.Members.Add( classDeclaration ); |
|
} |
|
classDictionary.Add( path, classDeclaration ); |
|
} |
|
return classDeclaration; |
|
} |
|
|
|
private static string GetTrimmedPathFromFullPath( string fmodPath ) |
|
{ |
|
return fmodPath.Split( new char[] { ':' }, 2 )[1]; |
|
} |
|
|
|
} |