1717namespace UdonSharpEditor
1818{
1919 #region Beta SDK sync mode menu editor
20- #if UDON_BETA_SDK
2120 internal class SyncModeMenu : EditorWindow
2221 {
2322 static SyncModeMenu menu ;
@@ -228,7 +227,6 @@ void ShowDropDown(Rect controlRect, Vector2 size)
228227 showAsDropDownMethod . Invoke ( this , new object [ ] { controlRect , size , popupLocationArray } ) ;
229228 }
230229 }
231- #endif
232230 #endregion
233231
234232 public static class UdonSharpGUI
@@ -1342,40 +1340,96 @@ public static bool DrawProgramSource(UnityEngine.Object target, bool drawScript
13421340
13431341 static readonly GUIContent ownershipTransferOnCollisionContent = new GUIContent ( "Allow Ownership Transfer on Collision" ,
13441342 "Transfer ownership on collision, requires a Collision component on the same game object" ) ;
1345-
1346- #if UDON_BETA_SDK
1343+
13471344 static MethodInfo dropdownButtonMethod ;
1348- #endif
13491345
13501346 internal static void DrawSyncSettings ( UdonBehaviour behaviour )
13511347 {
1352- #if UDON_BETA_SDK
13531348 UdonSharpProgramAsset programAsset = ( UdonSharpProgramAsset ) behaviour . programSource ;
13541349
1355- bool allowsSyncConfig = programAsset . behaviourSyncMode == BehaviourSyncMode . Any ;
1350+ EditorGUI . BeginDisabledGroup ( Application . isPlaying ) ;
13561351
1357- EditorGUI . BeginDisabledGroup ( EditorApplication . isPlaying || ! allowsSyncConfig ) ;
1352+ UdonBehaviour [ ] behavioursOnObject = behaviour . GetComponents < UdonBehaviour > ( ) ;
13581353
1359- Rect syncMethodRect = EditorGUILayout . GetControlRect ( ) ;
1360- int id = GUIUtility . GetControlID ( "DropdownButton" . GetHashCode ( ) , FocusType . Keyboard , syncMethodRect ) ;
1361- Rect dropdownRect = EditorGUI . PrefixLabel ( syncMethodRect , id , new GUIContent ( "Synchronization Method" ) ) ;
1354+ // Sanity checking for mixed sync modes
1355+ if ( behavioursOnObject . Length > 1 )
1356+ {
1357+ bool hasContinuousSync = false ;
1358+ bool hasReliableSync = false ;
1359+
1360+ foreach ( UdonBehaviour otherBehaviour in behavioursOnObject )
1361+ {
1362+ if ( otherBehaviour . Reliable )
1363+ hasReliableSync = true ;
1364+ else
1365+ hasContinuousSync = true ;
1366+ }
13621367
1363- if ( dropdownButtonMethod == null )
1364- dropdownButtonMethod = typeof ( EditorGUI ) . GetMethod ( "DropdownButton" , BindingFlags . NonPublic | BindingFlags . Static , null , new Type [ ] { typeof ( int ) , typeof ( Rect ) , typeof ( GUIContent ) , typeof ( GUIStyle ) } , null ) ;
1368+ if ( hasContinuousSync && hasReliableSync )
1369+ {
1370+ if ( programAsset . behaviourSyncMode == BehaviourSyncMode . NoVariableSync )
1371+ EditorGUILayout . HelpBox ( "NoVariableSync mode uses Continuous sync mode internally. You are mixing sync methods between UdonBehaviours on the same game object, this will cause all behaviours to use the sync method of the last component on the game object." , MessageType . Error ) ;
1372+ else
1373+ EditorGUILayout . HelpBox ( "You are mixing sync methods between UdonBehaviours on the same game object, this will cause all behaviours to use the sync method of the last component on the game object." , MessageType . Error ) ;
1374+ }
1375+ }
13651376
1366- if ( ( bool ) dropdownButtonMethod . Invoke ( null , new object [ ] { id , dropdownRect , new GUIContent ( behaviour . Reliable ? "Manual" : "Continuous" ) , EditorStyles . miniPullDown } ) )
1377+ // Dropdown for the sync settings
1378+ if ( programAsset . behaviourSyncMode != BehaviourSyncMode . NoVariableSync )
13671379 {
1368- SyncModeMenu . Show ( syncMethodRect , new UdonBehaviour [ ] { behaviour } ) ;
1380+ bool allowsSyncConfig = programAsset . behaviourSyncMode == BehaviourSyncMode . Any ;
1381+
1382+ EditorGUI . BeginDisabledGroup ( EditorApplication . isPlaying || ! allowsSyncConfig ) ;
1383+
1384+ Rect syncMethodRect = EditorGUILayout . GetControlRect ( ) ;
1385+ int id = GUIUtility . GetControlID ( "DropdownButton" . GetHashCode ( ) , FocusType . Keyboard , syncMethodRect ) ;
1386+ GUIContent dropdownContent = allowsSyncConfig ? new GUIContent ( "Synchronization Method" ) : new GUIContent ( "Synchronization Method" , "This sync mode is currently set by the UdonBehaviourSyncMode attribute on the script" ) ;
13691387
1370- GUIUtility . ExitGUI ( ) ;
1388+ Rect dropdownRect = EditorGUI . PrefixLabel ( syncMethodRect , id , dropdownContent ) ;
1389+
1390+ if ( dropdownButtonMethod == null )
1391+ dropdownButtonMethod = typeof ( EditorGUI ) . GetMethod ( "DropdownButton" , BindingFlags . NonPublic | BindingFlags . Static , null , new Type [ ] { typeof ( int ) , typeof ( Rect ) , typeof ( GUIContent ) , typeof ( GUIStyle ) } , null ) ;
1392+
1393+ if ( ( bool ) dropdownButtonMethod . Invoke ( null , new object [ ] { id , dropdownRect , new GUIContent ( behaviour . Reliable ? "Manual" : "Continuous" ) , EditorStyles . miniPullDown } ) )
1394+ {
1395+ SyncModeMenu . Show ( syncMethodRect , new UdonBehaviour [ ] { behaviour } ) ;
1396+
1397+ GUIUtility . ExitGUI ( ) ;
1398+ }
1399+
1400+ EditorGUI . EndDisabledGroup ( ) ;
1401+
1402+ bool newReliableState = behaviour . Reliable ;
1403+
1404+ // Handle auto setting of sync mode if the component has just been created
1405+ if ( programAsset . behaviourSyncMode == BehaviourSyncMode . Continuous && behaviour . Reliable )
1406+ newReliableState = false ;
1407+ else if ( programAsset . behaviourSyncMode == BehaviourSyncMode . Manual && ! behaviour . Reliable )
1408+ newReliableState = true ;
1409+
1410+ if ( newReliableState != behaviour . Reliable )
1411+ {
1412+ Undo . RecordObject ( behaviour , "Update sync mode" ) ;
1413+ behaviour . Reliable = newReliableState ;
1414+ }
13711415 }
13721416
1373- EditorGUI . EndDisabledGroup ( ) ;
1374- #else
1375- EditorGUI . BeginChangeCheck ( ) ;
1417+ // Validate that we don't have a VRC Object Sync on continuous synced objects since it is not valid
1418+ if ( behaviour . Reliable )
1419+ {
1420+ var objSync = behaviour . GetComponent < VRC . SDK3 . Components . VRCObjectSync > ( ) ;
13761421
1377- EditorGUI . BeginDisabledGroup ( Application . isPlaying ) ;
1378- bool newSyncPos = EditorGUILayout . Toggle ( "Synchronize Position" , behaviour . SynchronizePosition ) ;
1422+ #pragma warning disable CS0618 // Type or member is obsolete
1423+ if ( behaviour . SynchronizePosition )
1424+ #pragma warning restore CS0618 // Type or member is obsolete
1425+ EditorGUILayout . HelpBox ( "Manual sync cannot be used on GameObjects with Position Sync" , MessageType . Error ) ;
1426+ else if ( objSync )
1427+ EditorGUILayout . HelpBox ( "Manual sync cannot be used on GameObjects with VRC Object Sync" , MessageType . Error ) ;
1428+ }
1429+
1430+ // Position sync upgrade warnings & collision transfer handling
1431+ #pragma warning disable CS0618 // Type or member is obsolete
1432+ EditorGUI . BeginChangeCheck ( ) ;
13791433 bool newCollisionTransfer = behaviour . AllowCollisionOwnershipTransfer ;
13801434 if ( behaviour . GetComponent < Collider > ( ) != null )
13811435 {
@@ -1384,24 +1438,64 @@ internal static void DrawSyncSettings(UdonBehaviour behaviour)
13841438 if ( newCollisionTransfer )
13851439 EditorGUILayout . HelpBox ( "Collision transfer is currently bugged and can cause network spam that lags your world, use at your own risk." , MessageType . Warning ) ;
13861440 }
1387- else if ( newCollisionTransfer )
1441+ else if ( newCollisionTransfer )
13881442 {
13891443 newCollisionTransfer = false ;
13901444
13911445 GUI . changed = true ;
13921446 }
1393- EditorGUI . EndDisabledGroup ( ) ;
13941447
13951448 if ( EditorGUI . EndChangeCheck ( ) )
13961449 {
1397- Undo . RecordObject ( behaviour , "Change sync setting" ) ;
1398- behaviour . SynchronizePosition = newSyncPos ;
1450+ Undo . RecordObject ( behaviour , "Changed ownership transfer" ) ;
13991451 behaviour . AllowCollisionOwnershipTransfer = newCollisionTransfer ;
1452+ }
1453+
1454+ // For now we'll do a warning, later on we may add a validation pass that just converts everything automatically
1455+ if ( behaviour . SynchronizePosition )
1456+ {
1457+ var objectSync = behaviour . GetComponent < VRC . SDK3 . Components . VRCObjectSync > ( ) ;
1458+
1459+ if ( objectSync )
1460+ {
1461+ if ( behaviour . AllowCollisionOwnershipTransfer && ! objectSync . AllowCollisionOwnershipTransfer )
1462+ {
1463+ Undo . RecordObject ( behaviour , "Object sync owner transfer" ) ;
1464+ objectSync . AllowCollisionOwnershipTransfer = true ;
1465+ }
1466+
1467+ Undo . RecordObject ( behaviour , "Change sync position" ) ;
1468+ behaviour . SynchronizePosition = false ;
1469+ }
1470+ else
1471+ {
1472+ EditorGUILayout . HelpBox ( "This behaviour has sync position enabled on it, sync position is deprecated and you should now use the VRC Object Sync script." , MessageType . Warning ) ;
1473+ if ( GUILayout . Button ( "Switch to VRC Object Sync" ) )
1474+ {
1475+ var newObjSync = Undo . AddComponent < VRC . SDK3 . Components . VRCObjectSync > ( behaviour . gameObject ) ;
1476+ while ( UnityEditorInternal . ComponentUtility . MoveComponentUp ( newObjSync ) ) { }
1477+
1478+ UdonBehaviour [ ] behaviours = behaviour . GetComponents < UdonBehaviour > ( ) ;
1479+
1480+ bool usesCollisionTransfer = false ;
1481+
1482+ foreach ( UdonBehaviour otherBehaviour in behaviours )
1483+ {
1484+ usesCollisionTransfer |= otherBehaviour . AllowCollisionOwnershipTransfer ;
1485+
1486+ Undo . RecordObject ( behaviour , "Convert to VRC Object Sync" ) ;
1487+ behaviour . SynchronizePosition = false ;
1488+ behaviour . AllowCollisionOwnershipTransfer = false ;
1489+ }
14001490
1401- if ( PrefabUtility . IsPartOfPrefabInstance ( behaviour ) )
1402- PrefabUtility . RecordPrefabInstancePropertyModifications ( behaviour ) ;
1491+ Undo . RecordObject ( newObjSync , "Object sync collision transfer" ) ;
1492+ newObjSync . AllowCollisionOwnershipTransfer = newCollisionTransfer ;
1493+ }
1494+ }
14031495 }
1404- #endif
1496+ #pragma warning restore CS0618 // Type or member is obsolete
1497+
1498+ EditorGUI . EndDisabledGroup ( ) ;
14051499 }
14061500
14071501 /// <summary>
0 commit comments