AutomaticVersionning

From Unify Community Wiki
(Difference between revisions)
Jump to: navigation, search
(Integrated usage exemple picture)
(Versioning takes only one "n". Rebuilding everything)
Line 2: Line 2:
  
 
==Download==
 
==Download==
[https://drive.google.com/file/d/1ewrOR3Jwdtv_qI_RVV7aaSU2Z7sIXaCB/view?usp=sharing Versionning.cs]
+
[https://drive.google.com/file/d/1XjmpCXaWbnxcIDbJ5oKJemZZDnwOfPWI/view?usp=sharing Versioning.cs]
  
 
==Compatibility==
 
==Compatibility==

Revision as of 00:47, 4 October 2020

Author: Serge Billault

Contents

Download

Versioning.cs

Compatibility

. Unity versions: Unity 5.0 through Unity 2019.3.15f1 (Untested on Unity 2020+).
. Net compatibility level: 2.0 minimum - no dynamic methods.
. Unsafe code: None.
. Reflectivity: Yes.
. Networking: None.

Description

Versionning automatic generation.

. option ignore orders: Yes
. option ignore names: Yes
. accept generics: Yes
. accept nesteds: Yes
. optional hints: Yes (custom attribute [Versionning])

Usage

Copy script file in your Assets folder.

. Action required: none
. Setup required: none
. Scripting: "int version = YOUR_NAMESPACE.Versionning.Get( Versionning.OPTIONS.<options>, ...<type> or <types list>... );"

Versionning usage exemple reduced.jpg

Code (Versionning.cs)

using System;
using System.Collections.Generic;
using System.Reflection;
 
//************************************************************************************************
//
//************************************************************************************************
 
namespace YOUR_NAMESPACE
{
    //********************************************************************************************
    //
    //********************************************************************************************
 
    static public class CRC_32
    {
        //****************************************************************************************
        //
        //****************************************************************************************
 
               private const uint      m_poly  = 0XEDB88320;
 
        static private readonly uint[] m_table = new uint[ 256 ];
 
        //****************************************************************************************
        //
        //****************************************************************************************
 
        static CRC_32() 
        {
            uint temp      = 0;
 
            uint table_len = ( uint )m_table.Length;
 
            for( uint i = 0; i < table_len; ++i ) 
            {
                temp = i;
 
                for( int j = 8; j > 0; --j ) 
                {
                    if( ( temp & 1 ) == 1 )  { temp = ( uint )( ( temp >> 1 ) ^ m_poly ); }
 
                    else                     { temp >>= 1; }
                }
 
                m_table[ i ] = temp;
            }
        } 
 
        //****************************************************************************************
        //
        //****************************************************************************************
 
        public static uint Compute( byte[] bytes )
        {
            if( bytes == null ) return 0;
 
            uint crc = 0XFFFFFFFF;
 
            for( int i = 0, len = bytes.Length; i < len; ++i ) 
            {
                byte index = ( byte )( ( ( crc ) & 0XFF ) ^ bytes[ i ] );
 
                crc = ( uint )( ( crc >> 8 ) ^ m_table[ index ] );
            }
 
            return ~crc;
        }
 
        //****************************************************************************************
        //
        //****************************************************************************************
 
        public static uint Compute( string str )
        {
            if( string.IsNullOrEmpty( str ) ) return 0;
 
            byte[] bytes = System.Text.Encoding.ASCII.GetBytes( str );
 
            return Compute( bytes );
        }
    }
 
    //********************************************************************************************
    //
    //********************************************************************************************
 
    static public class REFLECTION
    {
        //****************************************************************************************
        //
        //****************************************************************************************
 
        static public bool TypeImplementInterface( Type type, Type interfaceT )
        {
            if( type                   == null  ) return false;
 
            if( interfaceT             == null  ) return false;
 
            if( type.IsInterface       == true  ) return false;
 
            if( interfaceT.IsInterface == false ) return false;
 
 
            Type[] interfaces = type.GetInterfaces();
 
            for( int i = 0, nb_interfaces = interfaces.Length; i < nb_interfaces; ++i )
            {
                if( object.ReferenceEquals( interfaces[ i ], interfaceT ) )
                {
                    return true;
                }
            }
 
            return false;
        }
 
        //****************************************************************************************
        //
        //****************************************************************************************
 
        static public List< Type > GetSubClassesOf( Type T, Assembly A = null )
        {
            List< Type > result = new List< Type >( 16 );
 
            if( T             == null  ) return result;
 
            if( T.IsInterface == true  ) return result;
 
 
            Assembly[] assemblies = ( A != null ) ? new Assembly[ 1 ] { A } : ( ( AppDomain.CurrentDomain != null ) ? AppDomain.CurrentDomain.GetAssemblies() : new Assembly[ 0 ] );
 
            for( int a = 0, nb_assemblies = assemblies.Length; a < nb_assemblies; ++a )
            {
                Type[] types = assemblies[ a ].GetTypes();
 
                foreach( Type type in types )
                {
                    if( type.IsSubclassOf( T ) ) result.Add( type );
                }
            }
 
            return result;
        }
 
        //****************************************************************************************
        //
        //****************************************************************************************
 
        static public Type[] GetTypesImplentingInterface( Type interfaceT )
        {
            List< Type > result = new List< Type >( 16 );
 
            if( interfaceT             == null  ) return result.ToArray();
 
            if( interfaceT.IsInterface == false ) return result.ToArray();
 
 
            Assembly[] assemblies = ( AppDomain.CurrentDomain != null ) ? AppDomain.CurrentDomain.GetAssemblies() : new Assembly[ 0 ];
 
            for( int a = 0, nb_assemblies = assemblies.Length; a < nb_assemblies; ++a )
            {
                Type[] types = assemblies[ a ].GetTypes();
 
                for( int t = 0, nb_types = types.Length; t < nb_types; ++t )
                {
                    Type type = types[ t ];
 
                    if( ( type.IsInterface == false ) && ( TypeImplementInterface( type, interfaceT ) ) )
                    {
                        result.Add( type );
                    }
                }
            }
 
            return result.ToArray();
        }
    }
 
    //********************************************************************************************
    //
    //********************************************************************************************
 
    [ AttributeUsage( AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field, AllowMultiple = false, Inherited = true ) ]
 
    public class VersioningAttribute : Attribute {}
 
    //********************************************************************************************
    //
    //********************************************************************************************
 
    public class Versionning : IComparer< FieldInfo >
    {
        //****************************************************************************************
        //
        //****************************************************************************************
 
        [ System.Flags ] public enum OPTIONS 
        { 
            STRICT       = 0X0, // any change             impact version number
 
            IGNORE_NAMES = 0X1, // changing names do not  impact version number
 
            IGNORE_ORDER = 0X2, // changing order do not  impact version number
 
            IGNORE_ALL   = 0X3  // only adding / removing impact version number
        }
 
        //****************************************************************************************
        //
        //****************************************************************************************
 
        static public int Get( OPTIONS opts, Type          type  ) { return new Versionning( opts, type  ).m_crc; }
 
        static public int Get( OPTIONS opts, params Type[] types ) { return new Versionning( opts, types ).m_crc; }
 
        //****************************************************************************************
        //
        //****************************************************************************************
 
        public class Dependency
        {
            public Type                       m_type   = null;
 
            public readonly List< FieldInfo > m_fields = new List< FieldInfo >();
 
            public Dependency( Type type ) { m_type = type; }
        }
 
        //****************************************************************************************
        //
        //****************************************************************************************
 
        public class Scope : List< Type >
        {
            new public void Add( Type type ) { if( Contains( type ) == false ) base.Add( type ); }
        }
 
        //****************************************************************************************
        //
        //****************************************************************************************
 
        public const string SEM_ARRAY_START  = "[";
 
        public const char   SEM_ARRAY_END    = ']';
 
        public const string SEM_OBJECT_START = "{";
 
        public const char   SEM_OBJECT_END   = '}';
 
        public const char   SEM_SEP          = ',';
 
        public const char   SEM_SPACE        = ' ';
 
        //****************************************************************************************
        //
        //****************************************************************************************
 
        private readonly List< Dependency > m_deps = new List< Dependency >();
 
        private int                         m_crc  = 0;
 
        private OPTIONS                     m_opts = OPTIONS.STRICT;
 
        //****************************************************************************************
        //
        //****************************************************************************************
 
        private      Versionning( OPTIONS opts, Type          type  ) { m_opts = opts; Build( new Type[] { type } ); }
 
        private      Versionning( OPTIONS opts, params Type[] types ) { m_opts = opts; Build( types ); }
 
        private void Build      (               params Type[] types ) { BuildManifest( types ); ComputeCrc(); }
 
        //****************************************************************************************
        //
        //****************************************************************************************
 
        private void Clear()
        {
            m_deps.Clear();
 
            m_crc = 0;
        }
 
        //****************************************************************************************
        //
        //****************************************************************************************
 
        private bool AcceptType( Type type )
        {
            if( type == null )                                             return false;
 
            if( type == typeof( object ) )                                 return false;
 
            if( type.GetCustomAttribute< VersioningAttribute >() != null ) return true;
 
 
            if( type.IsInterface    == true  ) return false;
 
            if( type.IsAbstract     == true  ) return false;
 
            if( type.IsSealed       == true  ) return false;
 
            if( type.IsGenericType  == true  ) return false;
 
            if( type.IsSerializable == false ) return false;
 
            return true;
        }
 
        //****************************************************************************************
        //
        //****************************************************************************************
 
        private bool AcceptType( Type type, Type[] exceptions )
        {
            if( exceptions != null )
            {
                for( int e = 0, count = exceptions.Length; e < count; ++e )
                {
                    Type exception_t = exceptions[ e ];
 
                    if( ( object.ReferenceEquals( type, exception_t ) ) || ( REFLECTION.TypeImplementInterface( type, exception_t ) ) )
                    {
                        return true;
                    }
                }
            }
 
            return AcceptType( type );
        }
 
        //****************************************************************************************
        //
        //****************************************************************************************
 
        private void BuildManifest( params Type[] Types )
        {
            //************************************************************************************
            //
            //************************************************************************************
 
            Clear();
 
            //************************************************************************************
            //
            //************************************************************************************
 
            Scope scope = new Scope();
 
            foreach( Type type in Types )
            {
                if( type.IsInterface )
                {
                    Type[] types = REFLECTION.GetTypesImplentingInterface( type );
 
                    for( int impl = 0, nb_impls = types.Length; impl < nb_impls; ++impl )
                    {
                        Type implementation = types[ impl ];
 
                        if( AcceptType( implementation, Types ) )
                        {
                            scope.Add ( implementation );
                        }
                    }
                }
                else
                {
                    if( AcceptType( type, Types ) )
                    {
                        scope.Add ( type );
                    }
                }
            }
 
            //************************************************************************************
            //
            //************************************************************************************
 
            for( int cur = 0; cur < scope.Count; ++cur )
            {
                //********************************************************************************
                //
                //********************************************************************************
 
                Type cur_scope = scope[ cur ];
 
                if( cur_scope.BaseType != null )
                {
                    if( AcceptType( cur_scope.BaseType, Types ) )
                    {
                        scope.Add ( cur_scope.BaseType );
                    }
                }
 
                //********************************************************************************
                //
                //********************************************************************************
 
                Type[] generics = cur_scope.GetGenericArguments();
 
                for( int g = 0, nb_generics = generics.Length; g < nb_generics; ++g )
                {
                    Type generic = generics[ g ];
 
                    if( AcceptType( generic, Types ) )
                    {
                        scope.Add ( generic );
                    }
                }
 
                //********************************************************************************
                //
                //********************************************************************************
 
                Type[] nesteds = cur_scope.GetNestedTypes( ( BindingFlags )( -1 ) );
 
                for( int n = 0, nb_nested = nesteds.Length; n < nb_nested; ++n )
                {
                    Type nested = nesteds[ n ];
 
                    if( AcceptType( nested, Types ) )
                    {
                        scope.Add ( nested );
                    }
                }
 
                //********************************************************************************
                //
                //********************************************************************************
 
                Dependency  dep    = new Dependency( cur_scope );
 
                FieldInfo[] fields = dep.m_type.GetFields( ( BindingFlags )( -1 ) );
 
                m_deps.Add( dep );
 
 
                for( int f = 0, nb_infos = fields.Length; f < nb_infos; ++f )
                {
                    FieldInfo field = fields[ f ];
 
                    if( field.FieldType.IsSerializable )
                    {
                        dep.m_fields.Add( field );
                    }
 
                    if( AcceptType( field.FieldType, Types ) )
                    {
                        scope.Add ( field.FieldType );
                    }
                }
            }
        }
 
        //****************************************************************************************
        //
        //****************************************************************************************
 
        public int Compare( FieldInfo l, FieldInfo r )
        {
            bool   ignore_names = ( ( m_opts & OPTIONS.IGNORE_NAMES ) != 0 );
 
            string l_name       = ignore_names ? l.FieldType.FullName : l.FieldType.FullName + l.Name;
 
            string r_name       = ignore_names ? r.FieldType.FullName : r.FieldType.FullName + r.Name;
 
            return string.Compare( l_name, r_name, StringComparison.Ordinal ); 
        }
 
        //****************************************************************************************
        //
        //****************************************************************************************
 
        private string BuildDependencyOutput( Dependency dep )
        {
            List< FieldInfo > fields     = dep.m_fields;
 
            int               fields_cnt = fields.Count;
 
            int               last       = ( fields_cnt > 0 ) ? fields_cnt - 1 : 0;
 
 
            if( ( m_opts & OPTIONS.IGNORE_ORDER ) != 0 )
            {
                fields.Sort( this );
            }
 
 
            string output  = "\r\n\t"   + SEM_OBJECT_START;
 
                   output += "\r\n\t\t" + dep.m_type.Name;
 
            for( int fld = 0; fld < fields_cnt; ++fld )
            {
                FieldInfo field = fields[ fld ];
 
                string    name  = ( ( m_opts & OPTIONS.IGNORE_NAMES ) != 0 ) ? string.Empty : SEM_SPACE + field.Name;
 
                output += "\r\n\t\t* " + field.FieldType.FullName + name;
 
                if( fld != last ) output += SEM_SEP;
            }
 
            output += "\r\n\t" + SEM_OBJECT_END;
 
            return output;
        }
 
        //****************************************************************************************
        //
        //****************************************************************************************
 
        private void ComputeCrc()
        {
            string output = SEM_ARRAY_START;
 
            for( int dependency = 0; dependency < m_deps.Count; ++dependency )
            {
                Dependency dep = m_deps[ dependency ];
 
                output += BuildDependencyOutput( dep );
 
                if( dependency != ( m_deps.Count - 1 ) ) output += SEM_SEP;
            }
 
            output += "\r\n" + SEM_ARRAY_END;
 
            m_crc   = ( int )CRC_32.Compute( output ); 
 
 
            #if false
 
                UnityEngine.Debug.Log( output );
 
            #endif
        }
    }
}
Personal tools
Namespaces

Variants
Actions
Navigation
Extras
Toolbox