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(); } } }
public virtual void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) { // 客户端与服务端都需要注册序列化器. var collection = default(GhostPrefabCollectionComponent); var conversionTarget = GetConversionTarget(dstManager.World); // 查询出可用的Ghost预制体 _enabledGhosts = GetGhosts(); collection.ServerPrefabs = dstManager.CreateEntity(); var serverPrefabs = new NativeList <GhostPrefabBuffer>(Allocator.Temp); int ghostType = 0; foreach (var ghost in _enabledGhosts) { var orig = ghost.prefab.Type; Entity ent = GameObjectConversionUtility.ConvertGameObjectHierarchy(ghost.prefab.gameObject, conversionSystem.ForkSettings(1)); dstManager.SetComponentData(ent, new GhostComponent { GhostType = ghostType }); GhostPrefabType prefabType = orig == GhostAuthoringComponent.ClientInstanceType.Interpolated ? GhostPrefabType.InterpolatedClient : GhostPrefabType.PredictedClient; var ghostPrefab = new GhostPrefabBuffer { Value = ent, GhostType = ghostType, PrefabType = prefabType, IsOwner = orig == GhostAuthoringComponent.ClientInstanceType.OwnerPredicted && ghost.prefab.GetComponent <GhostOwnerAuthoringComponent>() }; NativeArray <ComponentType> componentTypes = dstManager.GetComponentTypes(ent); componentTypes.Dispose(); serverPrefabs.Add(ghostPrefab); ++ghostType; } dstManager.AddBuffer <GhostPrefabBuffer>(collection.ServerPrefabs).AddRange(serverPrefabs); serverPrefabs.Dispose(); //======================================================================================================= // 普通的预制体转换后的Entity PrefabCollectionSystem prefabCollectionSystem = dstManager.World.GetOrCreateSystem <PrefabCollectionSystem>(); prefabCollectionSystem.Prefabs = new NativeArray <PrefabItem>(this.ghostCollectionConfig.Prefabs.Count, Allocator.Persistent); for (int i = 0; i < this.ghostCollectionConfig.Prefabs.Count; i++) { Entity ent = conversionSystem.GetPrimaryEntity(ghostCollectionConfig.Prefabs[i]); var item = new PrefabItem { Value = ent, Type = i }; prefabCollectionSystem.Prefabs[i] = item; } // Debug.Log($"转换Prefabs: {prefabCollectionSystem.Prefabs.Length}"); //======================================================================================================= if (conversionTarget == TargetWorld.Client) { ghostType = 0; collection.ClientInterpolatedPrefabs = dstManager.CreateEntity(); collection.ClientPredictedPrefabs = dstManager.CreateEntity(); var predictedList = new NativeList <GhostPrefabBuffer>(Allocator.Temp); var interpolatedList = new NativeList <GhostPrefabBuffer>(Allocator.Temp); foreach (var ghost in _enabledGhosts) { var orig = ghost.prefab.Type; ghost.prefab.Type = GhostAuthoringComponent.ClientInstanceType.Interpolated; Entity interpolatedEnt = GameObjectConversionUtility.ConvertGameObjectHierarchy(ghost.prefab.gameObject, conversionSystem.ForkSettings(2)); dstManager.SetComponentData(interpolatedEnt, new GhostComponent { GhostType = ghostType }); interpolatedList.Add(new GhostPrefabBuffer { Value = interpolatedEnt, GhostType = ghostType, PrefabType = GhostPrefabType.InterpolatedClient }); ghost.prefab.Type = GhostAuthoringComponent.ClientInstanceType.Predicted; Entity predictedEnt = GameObjectConversionUtility.ConvertGameObjectHierarchy(ghost.prefab.gameObject, conversionSystem.ForkSettings(2)); dstManager.SetComponentData(predictedEnt, new GhostComponent { GhostType = ghostType }); predictedList.Add(new GhostPrefabBuffer { Value = predictedEnt, GhostType = ghostType, PrefabType = GhostPrefabType.PredictedClient }); ghost.prefab.Type = orig; ++ghostType; } dstManager.AddBuffer <GhostPrefabBuffer>(collection.ClientPredictedPrefabs).AddRange(predictedList); dstManager.AddBuffer <GhostPrefabBuffer>(collection.ClientInterpolatedPrefabs) .AddRange(interpolatedList); predictedList.Dispose(); interpolatedList.Dispose(); } dstManager.AddComponentData(entity, collection); }