2025-03-20 10:34:20 +08:00
using System ;
2024-03-07 21:22:48 +08:00
using System.Collections.Generic ;
2024-09-12 01:35:37 +08:00
using System.Linq ;
2024-03-07 03:18:00 +08:00
using System.Text ;
using UnityEngine ;
namespace DCFApixels.DragonECS.Unity.Editors
{
2024-04-29 22:12:51 +08:00
internal static partial class UnityEditorUtility
2024-03-07 03:18:00 +08:00
{
#region TransformFieldName
2024-03-10 04:56:29 +08:00
public static string TransformToUpperName ( string name )
{
if ( name . Length < = 0 )
{
return name ;
}
StringBuilder b = new StringBuilder ( ) ;
bool nextWorld = true ;
bool prewIsUpper = false ;
for ( int i = 0 ; i < name . Length ; i + + )
{
char c = name [ i ] ;
if ( char . IsLetter ( c ) = = false )
{
nextWorld = true ;
prewIsUpper = false ;
continue ;
}
bool isUpper = char . IsUpper ( c ) ;
if ( isUpper )
{
if ( nextWorld = = false & & prewIsUpper = = false )
{
b . Append ( '_' ) ;
}
}
b . Append ( char . ToUpper ( c ) ) ;
nextWorld = false ;
prewIsUpper = isUpper ;
}
return b . ToString ( ) ;
}
2024-03-07 03:18:00 +08:00
public static string TransformFieldName ( string name )
{
if ( name . Length < = 0 )
{
return name ;
}
StringBuilder b = new StringBuilder ( ) ;
bool nextWorld = true ;
bool prewIsUpper = false ;
for ( int i = 0 ; i < name . Length ; i + + )
{
char c = name [ i ] ;
if ( char . IsLetter ( c ) = = false )
{
nextWorld = true ;
prewIsUpper = false ;
continue ;
}
bool isUpper = char . IsUpper ( c ) ;
if ( isUpper )
{
if ( nextWorld = = false & & prewIsUpper = = false )
{
b . Append ( ' ' ) ;
nextWorld = true ;
}
}
if ( nextWorld )
{
b . Append ( char . ToUpper ( c ) ) ;
}
else
{
b . Append ( c ) ;
}
nextWorld = false ;
prewIsUpper = isUpper ;
}
return b . ToString ( ) ;
}
#endregion
2024-04-29 22:12:51 +08:00
}
}
#if UNITY_EDITOR
namespace DCFApixels.DragonECS.Unity.Editors
{
2025-03-20 10:34:20 +08:00
using DCFApixels.DragonECS.Unity.Internal ;
2024-09-29 15:59:14 +08:00
using UnityEditor ;
2024-12-08 15:38:04 +08:00
using Assembly = System . Reflection . Assembly ;
2024-09-29 15:59:14 +08:00
2024-04-29 22:12:51 +08:00
[InitializeOnLoad]
internal static partial class UnityEditorUtility
{
static UnityEditorUtility ( )
{
2025-03-20 10:34:20 +08:00
const int PREWARMUP_LIST_SIZE = 64 ;
2025-03-10 23:03:03 +08:00
EcsWorld . ResetStaticState ( ) ;
2025-03-20 10:34:20 +08:00
UnityDebugService . Activate ( ) ;
2025-03-10 23:03:03 +08:00
2024-12-08 15:38:04 +08:00
_integrationAssembly = typeof ( UnityEditorUtility ) . Assembly ;
2025-03-20 10:34:20 +08:00
List < Type > serializableTypes = new List < Type > ( PREWARMUP_LIST_SIZE ) ;
List < TypeMeta > typeWithMetaIDMetas = new List < TypeMeta > ( PREWARMUP_LIST_SIZE ) ;
List < TypeMeta > serializableTypeWithMetaIDMetas = new List < TypeMeta > ( PREWARMUP_LIST_SIZE ) ;
List < EntityEditorBlockDrawer > entityEditorBlockDrawers = new List < EntityEditorBlockDrawer > ( PREWARMUP_LIST_SIZE ) ;
2024-09-16 19:31:01 +08:00
foreach ( var assembly in AppDomain . CurrentDomain . GetAssemblies ( ) )
{
2024-10-01 19:05:51 +08:00
//var targetTypes = assembly.GetTypes().Where(type =>
// (type.IsGenericType || type.IsAbstract || type.IsInterface) == false &&
// type.IsSubclassOf(typeof(UnityObject)) == false &&
// type.GetCustomAttribute<SerializableAttribute>() != null);
2025-03-10 13:08:18 +08:00
foreach ( var type in assembly . GetTypes ( ) )
{
2025-03-20 10:34:20 +08:00
bool hasMetaID = false ;
if ( TypeMeta . TryGetCustomMeta ( type , out TypeMeta meta ) & & meta . IsHasMetaID ( ) )
2025-03-10 13:08:18 +08:00
{
2025-03-20 10:34:20 +08:00
typeWithMetaIDMetas . Add ( meta ) ;
hasMetaID = true ;
2025-03-10 13:08:18 +08:00
}
2024-09-16 19:31:01 +08:00
2025-03-20 10:34:20 +08:00
if ( type . IsConcreteType ( ) )
{
if ( typeof ( EntityEditorBlockDrawer ) . IsAssignableFrom ( type ) )
{
var drawer = ( EntityEditorBlockDrawer ) Activator . CreateInstance ( type ) ;
entityEditorBlockDrawers . Add ( drawer ) ;
}
if ( type . IsUnityObject ( ) = = false & & type . GetConstructor ( Type . EmptyTypes ) ! = null )
{
serializableTypes . Add ( type ) ;
if ( hasMetaID )
{
serializableTypeWithMetaIDMetas . Add ( meta ) ;
}
}
}
}
2024-09-16 19:31:01 +08:00
}
2024-09-29 15:59:14 +08:00
_serializableTypes = serializableTypes . ToArray ( ) ;
2025-03-20 10:34:20 +08:00
_typeWithMetaIDMetas = typeWithMetaIDMetas . ToArray ( ) ;
_serializableTypeWithMetaIDMetas = serializableTypeWithMetaIDMetas . ToArray ( ) ;
2025-03-10 13:08:18 +08:00
_entityEditorBlockDrawers = entityEditorBlockDrawers . ToArray ( ) ;
2024-10-01 09:09:40 +08:00
2025-03-20 10:34:20 +08:00
_metaIDCollisions = MetaID . FindMetaIDCollisions ( _typeWithMetaIDMetas ) ;
IsHasAnyMetaIDCollision = _metaIDCollisions . IsHasAnyCollision ;
if ( _metaIDCollisions . IsHasAnyCollision )
{
StringBuilder log = new StringBuilder ( ) ;
log . Append ( "MetaID identifier collisions detected. Some functions that use MetaID were disabled until the collisions were fixed. List of collisions:\r\n" ) ;
{
int i = 0 ;
foreach ( var collision in _metaIDCollisions )
{
i + + ;
log . Append ( '├' ) ;
log . Append ( $"ID: {collision.MetaID}\r\n" ) ;
int j = 0 ;
foreach ( var meta in collision )
{
j + + ;
log . Append ( '│' ) ;
if ( j = = collision . Count )
{
log . Append ( '└' ) ;
}
else
{
log . Append ( '├' ) ;
}
log . Append ( $"Type: {meta.TypeName}\r\n" ) ;
}
}
}
Debug . LogError ( log . ToString ( ) ) ;
}
foreach ( var item in _typeWithMetaIDMetas )
2024-10-01 09:09:40 +08:00
{
_metaIDTypePairs [ item . MetaID ] = item . Type ;
}
2024-09-16 19:31:01 +08:00
//Array.Sort(_serializableTypes, (a, b) => string.Compare(a.AssemblyQualifiedName, b.AssemblyQualifiedName, StringComparison.Ordinal));
//_noHiddenSerializableTypes = _serializableTypes.Where(o => {
// var atr = o.GetCustomAttribute<MetaTagsAttribute>();
// return atr != null && atr.Tags.Contains(MetaTags.HIDDEN);
//}).ToArray();
2024-04-29 22:12:51 +08:00
}
2024-09-29 15:59:14 +08:00
2025-03-21 19:59:23 +08:00
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void OnLoad ( )
{
EcsWorld . ResetStaticState ( ) ;
UnityDebugService . Activate ( ) ;
}
2024-12-08 15:38:04 +08:00
internal static readonly Assembly _integrationAssembly ;
2024-09-16 19:31:01 +08:00
internal static readonly Type [ ] _serializableTypes ;
2025-03-20 10:34:20 +08:00
internal static readonly TypeMeta [ ] _typeWithMetaIDMetas ;
2024-09-29 15:59:14 +08:00
internal static readonly TypeMeta [ ] _serializableTypeWithMetaIDMetas ;
2025-03-20 10:34:20 +08:00
internal static readonly EntityEditorBlockDrawer [ ] _entityEditorBlockDrawers ;
internal static readonly MetaID . CollisionList _metaIDCollisions ;
public static readonly bool IsHasAnyMetaIDCollision ;
2024-09-29 23:31:12 +08:00
private static readonly Dictionary < string , Type > _metaIDTypePairs = new Dictionary < string , Type > ( ) ;
public static bool TryGetTypeForMetaID ( string metaID , out Type type )
{
return _metaIDTypePairs . TryGetValue ( metaID , out type ) ;
}
2024-09-16 19:31:01 +08:00
//private static Type[] _noHiddenSerializableTypes;
2024-05-04 01:43:39 +08:00
private static GUIContent _singletonIconContent = null ;
2024-04-29 22:12:51 +08:00
private static GUIContent _singletonContent = null ;
2024-05-13 19:20:07 +08:00
private static GUIStyle _inputFieldCenterAnhor = null ;
2025-03-10 22:59:48 +08:00
private static Dictionary < Type , MonoScript > _scriptsAssets = new Dictionary < Type , MonoScript > ( 256 ) ;
2024-06-15 16:53:28 +08:00
2024-09-14 18:33:54 +08:00
internal static void ResetValues ( this SerializedProperty property , bool isExpand = false )
2024-09-15 00:00:32 +08:00
{
ResetValues_Internal ( property . Copy ( ) , isExpand , property . depth ) ;
}
private static void ResetValues_Internal ( SerializedProperty property , bool isExpand , int depth )
2024-09-14 18:33:54 +08:00
{
property . isExpanded = isExpand ;
switch ( property . propertyType )
{
case SerializedPropertyType . Generic :
try
//TODO хз как с этим работать, но это говно постоянно кидает
//InvalidOperationException: The operation is not possible when moved past all properties (Next returned false)
//и не дает инструментов и шансов этого избежать
{
2024-09-15 00:00:32 +08:00
bool x = true ;
while ( property . Next ( x ) & & property . depth > depth )
2024-09-14 18:33:54 +08:00
{
2024-09-15 00:00:32 +08:00
ResetValues_Internal ( property , isExpand , property . depth ) ;
x = false ;
2024-09-14 18:33:54 +08:00
}
}
catch ( Exception ) { }
break ;
case SerializedPropertyType . Integer :
property . intValue = default ;
break ;
case SerializedPropertyType . Boolean :
property . boolValue = default ;
break ;
case SerializedPropertyType . Float :
property . floatValue = default ;
break ;
case SerializedPropertyType . String :
property . stringValue = string . Empty ;
break ;
case SerializedPropertyType . Color :
property . colorValue = default ;
break ;
case SerializedPropertyType . ObjectReference :
2024-09-16 19:31:01 +08:00
property . objectReferenceValue = default ;
2024-09-14 18:33:54 +08:00
break ;
case SerializedPropertyType . LayerMask :
property . intValue = default ;
break ;
case SerializedPropertyType . Enum :
property . enumValueIndex = default ;
break ;
case SerializedPropertyType . Vector2 :
property . vector2Value = default ;
break ;
case SerializedPropertyType . Vector3 :
property . vector3Value = default ;
break ;
case SerializedPropertyType . Vector4 :
property . vector4Value = default ;
break ;
case SerializedPropertyType . Rect :
property . rectValue = default ;
break ;
case SerializedPropertyType . ArraySize :
property . ClearArray ( ) ;
break ;
case SerializedPropertyType . Character :
property . intValue = default ;
break ;
case SerializedPropertyType . AnimationCurve :
property . animationCurveValue = new AnimationCurve ( ) ;
break ;
case SerializedPropertyType . Bounds :
property . boundsValue = default ;
break ;
case SerializedPropertyType . Gradient :
#if UNITY_2022_1_OR_NEWER
property . gradientValue = new Gradient ( ) ; ;
#else
Debug . LogWarning ( $"Unsupported SerializedPropertyType: {property.propertyType}" ) ;
#endif
break ;
case SerializedPropertyType . Quaternion :
property . quaternionValue = Quaternion . identity ;
break ;
case SerializedPropertyType . ExposedReference :
2024-09-16 19:31:01 +08:00
property . objectReferenceValue = default ;
2024-09-14 18:33:54 +08:00
break ;
case SerializedPropertyType . FixedBufferSize :
for ( int i = 0 , iMax = property . fixedBufferSize ; i < iMax ; i + + )
{
property . GetFixedBufferElementAtIndex ( i ) . intValue = default ;
}
break ;
case SerializedPropertyType . Vector2Int :
property . vector2IntValue = default ;
break ;
case SerializedPropertyType . Vector3Int :
property . vector3IntValue = default ;
break ;
case SerializedPropertyType . RectInt :
property . rectIntValue = default ;
break ;
case SerializedPropertyType . BoundsInt :
property . boundsIntValue = default ;
break ;
case SerializedPropertyType . ManagedReference :
property . managedReferenceValue = default ;
break ;
case SerializedPropertyType . Hash128 :
property . hash128Value = default ;
break ;
default :
Debug . LogWarning ( $"Unsupported SerializedPropertyType: {property.propertyType}" ) ;
break ;
}
}
2024-06-15 16:53:28 +08:00
internal static bool TryGetScriptAsset ( Type type , out MonoScript script )
{
2025-03-10 22:59:48 +08:00
if ( _scriptsAssets . TryGetValue ( type , out script ) = = false )
2024-06-15 16:53:28 +08:00
{
script = null ;
2024-06-15 19:45:31 +08:00
string name = type . Name ;
int indexOf = name . LastIndexOf ( '`' ) ;
2024-09-10 19:13:31 +08:00
if ( indexOf > = 0 )
2024-06-15 19:45:31 +08:00
{
name = name . Substring ( 0 , indexOf ) ;
}
var guids = AssetDatabase . FindAssets ( $"{name} t:MonoScript" ) ;
2024-06-15 16:53:28 +08:00
for ( var i = 0 ; i < guids . Length ; i + + )
{
MonoScript textAsset = AssetDatabase . LoadAssetAtPath < MonoScript > ( AssetDatabase . GUIDToAssetPath ( guids [ i ] ) ) ;
2024-06-15 19:45:31 +08:00
if ( textAsset ! = null & & textAsset . name = = name )
2024-06-15 16:53:28 +08:00
{
script = textAsset ;
break ;
}
}
2025-03-10 22:59:48 +08:00
_scriptsAssets . Add ( type , script ) ;
2024-06-15 16:53:28 +08:00
}
return script ! = null ;
}
2024-03-07 03:18:00 +08:00
#region Label
2024-05-13 19:20:07 +08:00
public static GUIStyle GetInputFieldCenterAnhor ( )
{
if ( _inputFieldCenterAnhor = = null )
{
GUIStyle style = new GUIStyle ( EditorStyles . numberField ) ;
style . alignment = TextAnchor . MiddleCenter ;
style . font = EditorStyles . boldFont ;
_inputFieldCenterAnhor = style ;
}
return _inputFieldCenterAnhor ;
}
2024-03-10 08:10:58 +08:00
public static GUIContent GetLabelTemp ( )
{
if ( _singletonContent = = null )
{
_singletonContent = new GUIContent ( ) ;
}
2024-10-01 18:04:53 +08:00
_singletonContent . text = string . Empty ;
_singletonContent . tooltip = string . Empty ;
_singletonContent . image = null ;
2024-03-10 08:10:58 +08:00
return _singletonContent ;
}
2024-03-07 03:18:00 +08:00
public static GUIContent GetLabel ( string name , string tooltip = null )
{
if ( _singletonContent = = null )
{
_singletonContent = new GUIContent ( ) ;
}
_singletonContent . text = name ;
2024-03-09 09:42:04 +08:00
_singletonContent . image = null ;
_singletonContent . tooltip = tooltip ;
return _singletonContent ;
}
public static GUIContent GetLabel ( Texture image , string tooltip = null )
{
2024-05-04 01:43:39 +08:00
if ( _singletonIconContent = = null )
2024-03-09 09:42:04 +08:00
{
2024-05-04 01:43:39 +08:00
_singletonIconContent = new GUIContent ( ) ;
2024-03-09 09:42:04 +08:00
}
2024-05-04 01:43:39 +08:00
_singletonIconContent . text = string . Empty ;
_singletonIconContent . image = image ;
_singletonIconContent . tooltip = tooltip ;
return _singletonIconContent ;
2024-03-07 03:18:00 +08:00
}
#endregion
2025-03-10 19:41:17 +08:00
#region GetDefaultStyle
2025-03-10 17:56:18 +08:00
private static Texture2D _whiteTexture ;
private static GUIStyle _whiteStyle ;
private static GUIStyle _transperentBlackBackgrounStyle ;
2025-03-10 19:41:17 +08:00
private static GUIStyle _clearBackgrounStyle ;
2025-03-10 17:56:18 +08:00
public static Texture2D GetWhiteTexture ( )
{
if ( _whiteTexture = = null )
{
_whiteTexture = CreateTexture ( 2 , 2 , Color . white ) ;
}
return _whiteTexture ;
}
2025-03-10 19:41:17 +08:00
private static bool IsNotInitializedStyle ( GUIStyle style )
{
return style = = null | | style . normal . background = = null ;
}
2025-03-10 17:56:18 +08:00
public static GUIStyle GetWhiteStyle ( )
{
2025-03-10 19:41:17 +08:00
if ( IsNotInitializedStyle ( _whiteStyle ) )
2025-03-10 17:56:18 +08:00
{
_whiteStyle = CreateStyle ( GetWhiteTexture ( ) , GUI . skin . label ) ;
}
return _whiteStyle ;
}
public static GUIStyle GetTransperentBlackBackgrounStyle ( )
{
2025-03-10 19:41:17 +08:00
if ( IsNotInitializedStyle ( _transperentBlackBackgrounStyle ) )
2025-03-10 17:56:18 +08:00
{
_transperentBlackBackgrounStyle = CreateStyle ( CreateTexture ( 2 , 2 , new Color ( 0 , 0 , 0 , 0.2f ) ) , GUI . skin . label ) ;
}
return _transperentBlackBackgrounStyle ;
}
2025-03-10 19:41:17 +08:00
public static GUIStyle GetClearBackgrounStyle ( )
{
if ( IsNotInitializedStyle ( _clearBackgrounStyle ) )
{
_clearBackgrounStyle = CreateStyle ( CreateTexture ( 2 , 2 , new Color ( 0 , 0 , 0 , 0 ) ) , GUI . skin . label ) ;
}
return _clearBackgrounStyle ;
}
2025-03-10 17:56:18 +08:00
#endregion
2024-03-07 03:18:00 +08:00
#region GetStyle
2025-03-10 17:56:18 +08:00
private static GUIStyle CreateStyle ( Texture2D texture , GUIStyle referenceStyle = null )
2024-03-07 03:18:00 +08:00
{
2025-03-10 17:56:18 +08:00
if ( referenceStyle = = null )
{
referenceStyle = GUI . skin . box ;
}
2024-03-07 03:18:00 +08:00
GUIStyle result = new GUIStyle ( GUI . skin . box ) ;
2025-03-10 17:56:18 +08:00
Texture2D texture2D = texture ;
2024-03-07 03:18:00 +08:00
result . hover . background = texture2D ;
2024-05-02 21:02:16 +08:00
result . hover . scaledBackgrounds = Array . Empty < Texture2D > ( ) ;
2024-03-07 03:18:00 +08:00
result . focused . background = texture2D ;
2024-05-02 21:02:16 +08:00
result . focused . scaledBackgrounds = Array . Empty < Texture2D > ( ) ;
2024-03-07 03:18:00 +08:00
result . active . background = texture2D ;
2024-05-02 21:02:16 +08:00
result . active . scaledBackgrounds = Array . Empty < Texture2D > ( ) ;
2024-03-07 03:18:00 +08:00
result . normal . background = texture2D ;
2024-05-02 21:02:16 +08:00
result . normal . scaledBackgrounds = Array . Empty < Texture2D > ( ) ;
2024-03-07 03:18:00 +08:00
return result ;
}
private static Texture2D CreateTexture ( int width , int height , Color color )
{
var pixels = new Color [ width * height ] ;
for ( var i = 0 ; i < pixels . Length ; + + i )
2025-03-10 17:56:18 +08:00
{
2024-03-07 03:18:00 +08:00
pixels [ i ] = color ;
2025-03-10 17:56:18 +08:00
}
2024-03-07 03:18:00 +08:00
var result = new Texture2D ( width , height ) ;
result . SetPixels ( pixels ) ;
result . Apply ( ) ;
return result ;
}
#endregion
}
2024-03-07 21:22:48 +08:00
internal static class RuntimeComponentsUtility
{
public struct WorldData
{
2024-09-12 01:35:37 +08:00
public RuntimeComponentDropDown addComponentGenericMenu ;
2024-03-07 21:22:48 +08:00
public int poolsCount ;
2024-09-12 01:35:37 +08:00
public WorldData ( RuntimeComponentDropDown addComponentGenericMenu , int poolsCount )
2024-03-07 21:22:48 +08:00
{
this . addComponentGenericMenu = addComponentGenericMenu ;
this . poolsCount = poolsCount ;
}
}
//world id
private static Dictionary < EcsWorld , WorldData > _worldDatas = new Dictionary < EcsWorld , WorldData > ( ) ;
2024-09-12 01:35:37 +08:00
public static RuntimeComponentDropDown GetAddComponentGenericMenu ( EcsWorld world )
2024-03-07 21:22:48 +08:00
{
if ( _worldDatas . TryGetValue ( world , out WorldData data ) )
{
if ( data . poolsCount ! = world . PoolsCount )
{
data = CreateWorldData ( world ) ;
_worldDatas [ world ] = data ;
}
}
else
{
data = CreateWorldData ( world ) ;
_worldDatas [ world ] = data ;
world . AddListener ( new Listener ( world ) ) ;
}
return data . addComponentGenericMenu ;
}
private static WorldData CreateWorldData ( EcsWorld world )
{
2024-09-12 01:35:37 +08:00
IEnumerable < IEcsPool > pools = world . AllPools . ToArray ( ) . Where ( o = > o . IsNullOrDummy ( ) = = false ) ;
RuntimeComponentDropDown genericMenu = new RuntimeComponentDropDown ( pools ) ;
2024-03-07 21:22:48 +08:00
return new WorldData ( genericMenu , world . PoolsCount ) ;
}
private class Listener : IEcsWorldEventListener
{
private EcsWorld _world ;
public Listener ( EcsWorld world )
{
_world = world ;
}
public void OnReleaseDelEntityBuffer ( ReadOnlySpan < int > buffer ) { }
public void OnWorldDestroy ( )
{
_worldDatas . Remove ( _world ) ;
}
public void OnWorldResize ( int newSize ) { }
}
}
2024-03-07 03:18:00 +08:00
}
2024-03-07 21:22:48 +08:00
#endif