private ulong VariantPopup(SerializedComponentData comp, ulong variantHash) { if (!GhostAuthoringModifiers.VariantsCache.TryGetValue(comp.managedType.FullName, out var list)) { return(0); } int index = 0; if (variantHash != 0) { index = list.FindIndex(v => v.Attribute.VariantHash == variantHash); if (index < 0) { Debug.LogWarning($"Variation with hash {variantHash} not found."); index = 0; } } var names = list.Select(i => i.Attribute.DisplayName).ToArray(); var idx = EditorGUILayout.Popup(new GUIContent("Serialization Variant"), index, names); GUI.changed |= idx != index; return(list[idx].Attribute.VariantHash); }
void ShowComponent(ref SerializedComponentData comp) { GUIStyle style = new GUIStyle(EditorStyles.foldoutHeader); var prefabType = comp.attribute != null?comp.attribute.PrefabType:GhostPrefabType.All; var ownerPredictedSendType = comp.attribute != null?comp.attribute.OwnerPredictedSendType:GhostSendType.All; var sendForChildren = comp.attribute != null ? comp.attribute.SendDataForChildEntity : true; ulong variantHash = 0; int index = GetPrefabModifier(comp.name, comp.gameObject, out var modifier); //Apply prefab modifier only if they are meant to be different than the default. if (modifier != null) { if (modifier.PrefabType != GhostAuthoringComponent.ComponentOverride.UseDefaultValue) { prefabType = (GhostPrefabType)modifier.PrefabType; } if (modifier.OwnerPredictedSendType != GhostAuthoringComponent.ComponentOverride.UseDefaultValue) { ownerPredictedSendType = (GhostSendType)modifier.OwnerPredictedSendType; } if (modifier.SendToChild != GhostAuthoringComponent.ComponentOverride.UseDefaultValue) { sendForChildren = modifier.SendToChild == 0 ? false : true; } variantHash = modifier.ComponentVariant; } bool hasDataToSend = comp.fields.Length > 0 && (comp.entityIndex == 0 || sendForChildren); style.fontStyle = modifier == null ? hasDataToSend ? FontStyle.Bold : FontStyle.Normal : hasDataToSend ? FontStyle.BoldAndItalic : FontStyle.Italic; var text = String.Format("{0}{1} ({2}/{3}/{4}){5}", comp.entityIndex != 0 ? "Child " + (comp.entityIndex - 1).ToString() + ": " : "", comp.name, (prefabType & GhostPrefabType.Server) != 0 ? "S" : "-", (prefabType & GhostPrefabType.InterpolatedClient) != 0 ? "IC" : "-", (prefabType & GhostPrefabType.PredictedClient) != 0 ? "PC" : "-", modifier != null?"*":""); comp.isExpanded = EditorGUILayout.BeginFoldoutHeaderGroup(comp.isExpanded, text, style); var foldoutRect = GUILayoutUtility.GetLastRect(); bool canModifyComponent = comp.managedType.GetCustomAttribute <DontSupportPrefabOverrides>() == null; if (comp.isExpanded) { var modPrefab = modifier != null && modifier.PrefabType != GhostAuthoringComponent.ComponentOverride.UseDefaultValue; var modSendChild = modifier != null && modifier.SendToChild != GhostAuthoringComponent.ComponentOverride.UseDefaultValue; var modSendType = modifier != null && modifier.OwnerPredictedSendType != GhostAuthoringComponent.ComponentOverride.UseDefaultValue; GhostPrefabType newPrefab = prefabType; EditorGUI.BeginChangeCheck(); using (new EditorGUI.DisabledGroupScope(!canModifyComponent)) { modPrefab = AuthoringEditorHelper.ShowPrefabType(modPrefab, prefabType, ref newPrefab); modSendChild = AuthoringEditorHelper.ShowSendChild(comp, modSendChild, ref sendForChildren); modSendType = AuthoringEditorHelper.ShowSendType(modSendType, ref ownerPredictedSendType); //Changing variant will change the defaults values for the ghost attribute for the type variantHash = VariantPopup(comp, variantHash); } if (EditorGUI.EndChangeCheck()) { //If the prefab use default values there is not need to have a modifier. Remove bool useAllDefaults = !modPrefab && !modSendType && !modSendChild && variantHash == 0; if (useAllDefaults && modifier != null) { ComponentOverrides.RemoveAt(index); //Refresh the comp field to the theid default variant version ExtractComponentInfo((target as GhostAuthoringComponent)?.gameObject, ref comp); EditorUtility.SetDirty(target); } else if (!useAllDefaults) { if (modifier == null) { modifier = AddModifier(comp.name, comp.gameObject); } if (modifier.ComponentVariant != variantHash) { //Refresh the component fields values to reflect the current selected variant modifier.ComponentVariant = variantHash; ExtractComponentInfo((target as GhostAuthoringComponent)?.gameObject, ref comp); } modifier.PrefabType = modPrefab ? (int)newPrefab : GhostAuthoringComponent.ComponentOverride.UseDefaultValue; modifier.OwnerPredictedSendType = modSendType ? (int)ownerPredictedSendType : GhostAuthoringComponent.ComponentOverride.UseDefaultValue; modifier.SendToChild = modSendChild ? sendForChildren ? 1 : 0 : GhostAuthoringComponent.ComponentOverride.UseDefaultValue; EditorUtility.SetDirty(target); } } if ((prefabType & GhostPrefabType.Server) != 0) { EditorGUILayout.Separator(); EditorGUI.BeginDisabledGroup(true); EditorGUILayout.LabelField("Fields"); for (int fi = 0; fi < comp.fields.Length; ++fi) { ShowField(comp.fields[fi]); } EditorGUI.EndDisabledGroup(); } } EditorGUILayout.EndFoldoutHeaderGroup(); //Display context menu when user press the left mouse button that have some shortcuts. Options available: // - Remove the component from the ghost (set the prefab to type to 0) // - Reset the component to its default (remove the overrides) if (canModifyComponent && Event.current.type == EventType.MouseDown && Event.current.button == 1) { if (foldoutRect.Contains(Event.current.mousePosition)) { var typeFullName = comp.name; var gameObject = comp.gameObject; //Show context menu with some options var menu = new GenericMenu(); menu.AddItem(new GUIContent("Remove Component"), false, () => { //Add modifier if not present if (modifier == null) { modifier = AddModifier(typeFullName, gameObject); } modifier.PrefabType = 0; EditorUtility.SetDirty(target); }); if (modifier != null) { menu.AddItem(new GUIContent("Reset Default"), false, () => { ComponentOverrides.RemoveAt(index); EditorUtility.SetDirty(target); }); } else { menu.AddDisabledItem(new GUIContent("Reset Default")); } menu.ShowAsContext(); } } }