Esempio n. 1
0
    void GenerateSpawnSystem(GhostAuthoringComponent ghostInfo)
    {
        string ghostInterpolateComponents = "";
        string ghostPredictComponents     = "";

        for (int comp = 0; comp < ghostInfo.Components.Length; ++comp)
        {
            if (ghostInfo.Components[comp].interpolatedClient)
            {
                ghostInterpolateComponents +=
                    k_GhostSpawnComponentTemplate.Replace("$(GHOSTCOMPONENTTYPE)",
                                                          ghostInfo.Components[comp].name);
            }
            if (ghostInfo.Components[comp].predictedClient)
            {
                ghostPredictComponents +=
                    k_GhostSpawnComponentTemplate.Replace("$(GHOSTCOMPONENTTYPE)",
                                                          ghostInfo.Components[comp].name);
            }
        }

        var spawnData = k_GhostSpawnSystemTemplate
                        .Replace("$(GHOSTNAME)", target.name)
                        .Replace("$(GHOSTINTERPOLATEDCOMPONENTS)", ghostInterpolateComponents)
                        .Replace("$(GHOSTPREDICTEDCOMPONENTS)", ghostPredictComponents);

        File.WriteAllText(Path.Combine(assetPath, ghostInfo.SpawnSystemPath), spawnData);
    }
Esempio n. 2
0
    void GenerateGhost(GhostAuthoringComponent ghostInfo)
    {
        List <Type> allTypes = new List <Type>();

        foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
        {
            IEnumerable <Type> asmTypes = null;
            try
            {
                asmTypes = assembly.GetTypes();
            }
            catch (ReflectionTypeLoadException e)
            {
                asmTypes = e.Types.Where(t => t != null);
                Debug.LogWarning(
                    $"GhostImporter failed loading assembly: {(assembly.IsDynamic ? assembly.ToString() : assembly.Location)}");
            }

            allTypes.AddRange(asmTypes.Where(t => typeof(IComponentData).IsAssignableFrom(t) || typeof(IBufferElementData).IsAssignableFrom(t) || typeof(ISharedComponentData).IsAssignableFrom(t)));
        }

        // Update type of all fields
        for (int comp = 0; comp < ghostInfo.Components.Length; ++comp)
        {
            var componentTypes = allTypes.Where(t => t.Name == ghostInfo.Components[comp].name);
            if (componentTypes.Count() != 1)
            {
                Debug.LogError("Could not find the type or found several candidates: " + ghostInfo.Components[comp].name);
                return;
            }
            Type componentType = componentTypes.First();
            for (int field = 0; field < ghostInfo.Components[comp].fields.Length; ++field)
            {
                var fieldInfo = componentType.GetField(ghostInfo.Components[comp].fields[field].name);
                if (fieldInfo == null)
                {
                    Debug.LogError("Could not find field: " + ghostInfo.Components[comp].fields[field].name + " in componentType: " + ghostInfo.Components[comp].name);
                    return;
                }
                ghostInfo.Components[comp].fields[field].DataType = fieldInfo.FieldType;
            }
        }

        assetPath = AssetDatabase.GetAssetPath(target);
        if (assetPath == "")
        {
            assetPath = "Assets";
        }
        else
        {
            assetPath = Path.GetDirectoryName(assetPath);
        }

        GenerateSnapshotData(ghostInfo);
        GenerateSerializer(ghostInfo);
        GenerateSpawnSystem(ghostInfo);
        GenerateUpdateSystem(ghostInfo);
    }
Esempio n. 3
0
    void GenerateSerializer(GhostAuthoringComponent ghostInfo)
    {
        string ghostComponentType       = "";
        string assignGhostComponentType = "";
        string ghostComponentTypeCheck  = "";
        string ghostApply           = "";
        int    serverComponentCount = 0;

        for (int comp = 0; comp < ghostInfo.Components.Length; ++comp)
        {
            if (!ghostInfo.Components[comp].server)
            {
                continue;
            }
            ++serverComponentCount;
            ghostComponentTypeCheck +=
                k_SerializerComponentTypeCheckTemplate.Replace("$(GHOSTCOMPONENTTYPE)", ghostInfo.Components[comp].name);
            ghostComponentType +=
                k_SerializerComponentTypeTemplate.Replace("$(GHOSTCOMPONENTTYPE)", ghostInfo.Components[comp].name);
            assignGhostComponentType +=
                k_SerializerAssignComponentTypeTemplate.Replace("$(GHOSTCOMPONENTTYPE)", ghostInfo.Components[comp].name);
            if (ghostInfo.Components[comp].fields.Length > 0)
            {
                ghostComponentType +=
                    k_SerializerComponentTypeDataTemplate.Replace("$(GHOSTCOMPONENTTYPE)",
                                                                  ghostInfo.Components[comp].name);
                assignGhostComponentType +=
                    k_SerializerAssignComponentTypeDataTemplate.Replace("$(GHOSTCOMPONENTTYPE)",
                                                                        ghostInfo.Components[comp].name);
                ghostApply +=
                    k_SerializerAssignChunkArrayTemplate.Replace("$(GHOSTCOMPONENTTYPE)",
                                                                 ghostInfo.Components[comp].name);
                for (int field = 0; field < ghostInfo.Components[comp].fields.Length; ++field)
                {
                    ghostApply +=
                        k_SerializerAssignSnapshotTemplate.Replace("$(GHOSTCOMPONENTTYPE)",
                                                                   ghostInfo.Components[comp].name)
                        .Replace("$(GHOSTFIELDNAME)",
                                 ghostInfo.Components[comp].fields[field].name);
                }
            }
        }

        var serializerData = k_SerializerTemplate
                             .Replace("$(GHOSTNAME)", target.name)
                             .Replace("$(GHOSTIMPORTANCE)", ghostInfo.Importance)
                             .Replace("$(GHOSTCOMPONENTCHECK)", ghostComponentTypeCheck)
                             .Replace("$(GHOSTAPPLY)", ghostApply)
                             .Replace("$(GHOSTCOMPONENTCOUNT)", serverComponentCount.ToString())
                             .Replace("$(ASSIGNGHOSTCOMPONENTTYPES)", assignGhostComponentType)
                             .Replace("$(GHOSTCOMPONENTTYPES)", ghostComponentType);

        File.WriteAllText(Path.Combine(assetPath, ghostInfo.SerializerPath), serializerData);
    }
Esempio n. 4
0
 public override void OnInspectorGUI()
 {
     base.OnInspectorGUI();
     if (GUILayout.Button("Add Ghost Authoring Component"))
     {
         GameObject[] gameObjects = Selection.gameObjects;
         foreach (GameObject g in gameObjects)
         {
             GhostAuthoringComponent gac = g.AddComponent(typeof(GhostAuthoringComponent)) as GhostAuthoringComponent;
         }
     }
 }
        public void OnEnable()
        {
            ghost = (GhostAuthoringComponent)this.target;

            defaultClientInstantiationType = serializedObject.FindProperty(nameof(GhostAuthoringComponent.Type));
            ghostComponents = serializedObject.FindProperty(nameof(GhostAuthoringComponent.Components));

            // _serializers = ghost.Components.Where(f => f.isSerializer).ToList();
            //
            // _ghostList = new ReorderableList(_serializers,
            //     typeof(ComponentType),
            //     false, true, false, false);
            // _ghostList.drawHeaderCallback += DrawHeaderCallback;
            // _ghostList.drawElementCallback += DrawElementCallback;
        }
Esempio n. 6
0
        public static void SyncComponentList(GhostAuthoringComponent self)
        {
            using (var tempWorld = new World("TempGhostConversion"))
                using (var blobAssetStore = new BlobAssetStore())
                {
                    self.doNotStrip = true;
                    var convertedEntity = GameObjectConversionUtility.ConvertGameObjectHierarchy(self.gameObject, GameObjectConversionSettings.FromWorld(tempWorld, blobAssetStore));
                    self.doNotStrip = false;

                    // Build list of existing components
                    var toDelete = new Dictionary <string, int>();
                    for (int i = 0; i < self.Components.Length; ++i)
                    {
                        try
                        {
                            toDelete.Add(self.Components[i].entityIndex + self.Components[i].name, i);
                        }
                        catch (Exception e)
                        {
                            Debug.LogAssertion(e);
                        }
                    }

                    var newComponents = new List <GhostAuthoringComponent.GhostComponent>();
                    AddToComponentList(self, newComponents, toDelete, tempWorld, convertedEntity, 0);


                    if (tempWorld.EntityManager.HasComponent <LinkedEntityGroup>(convertedEntity))
                    {
                        var linkedEntityGroup = tempWorld.EntityManager.GetBuffer <LinkedEntityGroup>(convertedEntity);
                        for (int i = 1; i < linkedEntityGroup.Length; ++i)
                        {
                            AddToComponentList(self, newComponents, toDelete, tempWorld, linkedEntityGroup[i].Value, i);
                        }
                    }

                    self.Components = newComponents.ToArray();
                }
            EditorUtility.SetDirty(self);
        }
Esempio n. 7
0
        static void GenerateUpdateSystem(GhostAuthoringComponent ghostInfo, string ownerField, string assetPath, GhostCodeGen.Batch batch)
        {
            var codeGen      = new GhostCodeGen("Packages/com.unity.netcode/Editor/CodeGenTemplates/GhostUpdateSystem.cs");
            var replacements = new Dictionary <string, string>();

            var              ghostInterpolatedComponentFromEntitySet = new HashSet <string>();
            var              ghostPredictedComponentFromEntitySet    = new HashSet <string>();
            bool             interpolatedNeedsLinkedEntityGroup      = false;
            bool             predictedNeedsLinkedEntityGroup         = false;
            HashSet <string> imports = new HashSet <string>();

            imports.Add("Unity.Entities");
            HashSet <string> interpolatedEntityGroupTypes = new HashSet <string>();
            HashSet <string> predictedEntityGroupTypes    = new HashSet <string>();

            for (int comp = 0; comp < ghostInfo.Components.Length; ++comp)
            {
                if (ghostInfo.Components[comp].interpolatedClient && ghostInfo.Components[comp].entityIndex > 0 && ghostInfo.Components[comp].fields.Length > 0)
                {
                    interpolatedEntityGroupTypes.Add(ghostInfo.Components[comp].name);
                }
                if (ghostInfo.Components[comp].predictedClient && ghostInfo.Components[comp].entityIndex > 0 && ghostInfo.Components[comp].fields.Length > 0)
                {
                    predictedEntityGroupTypes.Add(ghostInfo.Components[comp].name);
                }
            }

            for (int comp = 0; comp < ghostInfo.Components.Length; ++comp)
            {
                if (!ghostInfo.Components[comp].server)
                {
                    continue;
                }
                if (ghostInfo.Components[comp].fields.Length == 0)
                {
                    continue;
                }
                var componentTypeName = GetShortName(ghostInfo.Components[comp]);

                var type           = ghostInfo.Components[comp].ShortName.Replace("+", ".");
                var fromEntityName = type.Replace(".", "");
                replacements.Clear();
                replacements.Add("GHOST_COMPONENT_TYPE", type);
                replacements.Add("GHOST_COMPONENT_TYPE_NAME", componentTypeName);
                replacements.Add("GHOST_COMPONENT_FROM_ENTITY_NAME", fromEntityName);
                replacements.Add("GHOST_ENTITY_INDEX", ghostInfo.Components[comp].entityIndex.ToString());

                if (ghostInfo.Components[comp].interpolatedClient &&
                    (ghostInfo.DefaultClientInstantiationType != GhostAuthoringComponent.ClientInstantionType.OwnerPredicted ||
                     ghostInfo.Components[comp].sendDataTo != GhostAuthoringComponent.ClientSendType.Predicted))
                {
                    imports.Add(ghostInfo.Components[comp].NamespaceName);

                    // When there are nested entities (or linked group entities) all of the components of the type
                    // we need from the group of entities (parent+children) should be accessed the same way, or we'll get native array aliasing
                    if (ghostInfo.Components[comp].entityIndex == 0 &&
                        !interpolatedEntityGroupTypes.Contains(ghostInfo.Components[comp].name))
                    {
                        codeGen.GenerateFragment("GHOST_INTERPOLATED_COMPONENT_TYPE", replacements);
                        codeGen.GenerateFragment("GHOST_INTERPOLATED_COMPONENT_REF", replacements);
                        codeGen.GenerateFragment("GHOST_INTERPOLATED_ASSIGN_COMPONENT_REF", replacements);
                        codeGen.GenerateFragment("GHOST_INTERPOLATED_COMPONENT_ARRAY", replacements);
                        codeGen.GenerateFragment("GHOST_INTERPOLATED_BEGIN_ASSIGN", replacements);
                        codeGen.GenerateFragment("GHOST_INTERPOLATED_END_ASSIGN", replacements);
                    }
                    else
                    {
                        interpolatedNeedsLinkedEntityGroup = true;
                        if (!ghostInterpolatedComponentFromEntitySet.Contains(type))
                        {
                            codeGen.GenerateFragment("GHOST_INTERPOLATED_COMPONENT_CHILD_REF", replacements);
                            codeGen.GenerateFragment("GHOST_INTERPOLATED_ASSIGN_COMPONENT_CHILD_REF", replacements);
                            ghostInterpolatedComponentFromEntitySet.Add(type);
                        }

                        codeGen.GenerateFragment("GHOST_INTERPOLATED_BEGIN_ASSIGN_CHILD", replacements);
                        codeGen.GenerateFragment("GHOST_INTERPOLATED_END_ASSIGN_CHILD", replacements);
                    }

                    for (int field = 0; field < ghostInfo.Components[comp].fields.Length; ++field)
                    {
                        replacements["GHOST_FIELD_NAME"] = ghostInfo.Components[comp].fields[field].name;
                        codeGen.GenerateFragment("GHOST_INTERPOLATED_ASSIGN", replacements);
                    }
                }

                if (ghostInfo.Components[comp].predictedClient &&
                    (ghostInfo.DefaultClientInstantiationType != GhostAuthoringComponent.ClientInstantionType.OwnerPredicted ||
                     ghostInfo.Components[comp].sendDataTo != GhostAuthoringComponent.ClientSendType.Interpolated))
                {
                    imports.Add(ghostInfo.Components[comp].NamespaceName);

                    // When there are nested entities (or linked group entities) all of the components of the type
                    // we need from the group of entities (parent+children) should be accessed the same way, or we'll get native array aliasing
                    if (ghostInfo.Components[comp].entityIndex == 0 &&
                        !predictedEntityGroupTypes.Contains(ghostInfo.Components[comp].name))
                    {
                        codeGen.GenerateFragment("GHOST_PREDICTED_COMPONENT_TYPE", replacements);
                        codeGen.GenerateFragment("GHOST_PREDICTED_COMPONENT_REF", replacements);
                        codeGen.GenerateFragment("GHOST_PREDICTED_ASSIGN_COMPONENT_REF", replacements);
                        codeGen.GenerateFragment("GHOST_PREDICTED_COMPONENT_ARRAY", replacements);
                        codeGen.GenerateFragment("GHOST_PREDICTED_BEGIN_ASSIGN", replacements);
                        codeGen.GenerateFragment("GHOST_PREDICTED_END_ASSIGN", replacements);
                    }
                    else
                    {
                        predictedNeedsLinkedEntityGroup = true;
                        if (!ghostPredictedComponentFromEntitySet.Contains(type))
                        {
                            codeGen.GenerateFragment("GHOST_PREDICTED_COMPONENT_CHILD_REF", replacements);
                            codeGen.GenerateFragment("GHOST_PREDICTED_ASSIGN_COMPONENT_CHILD_REF", replacements);
                            ghostPredictedComponentFromEntitySet.Add(type);
                        }

                        codeGen.GenerateFragment("GHOST_PREDICTED_BEGIN_ASSIGN_CHILD", replacements);
                        codeGen.GenerateFragment("GHOST_PREDICTED_END_ASSIGN_CHILD", replacements);
                    }

                    for (int field = 0; field < ghostInfo.Components[comp].fields.Length; ++field)
                    {
                        replacements["GHOST_FIELD_NAME"] = ghostInfo.Components[comp].fields[field].name;
                        codeGen.GenerateFragment("GHOST_PREDICTED_ASSIGN", replacements);
                    }
                }
            }
            if (interpolatedNeedsLinkedEntityGroup)
            {
                replacements.Clear();
                replacements.Add("GHOST_COMPONENT_TYPE", "LinkedEntityGroup");
                replacements.Add("GHOST_COMPONENT_TYPE_NAME", "LinkedEntityGroup");
                codeGen.GenerateFragment("GHOST_INTERPOLATED_READ_ONLY_COMPONENT_TYPE", replacements);
                codeGen.GenerateFragment("GHOST_INTERPOLATED_BUFFER_REF", replacements);
                codeGen.GenerateFragment("GHOST_INTERPOLATED_ASSIGN_BUFFER_REF", replacements);
                codeGen.GenerateFragment("GHOST_INTERPOLATED_BUFFER_ARRAY", replacements);
            }
            if (predictedNeedsLinkedEntityGroup)
            {
                replacements.Clear();
                replacements.Add("GHOST_COMPONENT_TYPE", "LinkedEntityGroup");
                replacements.Add("GHOST_COMPONENT_TYPE_NAME", "LinkedEntityGroup");
                codeGen.GenerateFragment("GHOST_PREDICTED_READ_ONLY_COMPONENT_TYPE", replacements);
                codeGen.GenerateFragment("GHOST_PREDICTED_BUFFER_REF", replacements);
                codeGen.GenerateFragment("GHOST_PREDICTED_ASSIGN_BUFFER_REF", replacements);
                codeGen.GenerateFragment("GHOST_PREDICTED_BUFFER_ARRAY", replacements);
            }

            replacements.Clear();
            replacements.Add("GHOST_NAME", ghostInfo.name);
            replacements.Add("GHOST_OWNER_FIELD", ownerField);
            if (ghostInfo.DefaultClientInstantiationType == GhostAuthoringComponent.ClientInstantionType.OwnerPredicted)
            {
                codeGen.GenerateFragment("GHOST_OWNER_PREDICTED_DEFAULT", replacements);
            }
            else if (ghostInfo.DefaultClientInstantiationType == GhostAuthoringComponent.ClientInstantionType.Predicted)
            {
                codeGen.GenerateFragment("GHOST_PREDICTED_DEFAULT", replacements);
            }

            replacements.Clear();
            foreach (var ns in imports)
            {
                if (ns != null && ns != "")
                {
                    replacements["GHOST_USING"] = ns;
                    codeGen.GenerateFragment("GHOST_USING_STATEMENT", replacements);
                }
            }

            replacements.Clear();
            replacements.Add("GHOST_NAME", ghostInfo.name);
            codeGen.GenerateFile(assetPath, ghostInfo.RootPath, ghostInfo.UpdateSystemPath, replacements, batch);
        }
Esempio n. 8
0
        static void GenerateSerializer(GhostAuthoringComponent ghostInfo, string assetPath, GhostCodeGen.Batch batch)
        {
            var codeGen      = new GhostCodeGen("Packages/com.unity.netcode/Editor/CodeGenTemplates/GhostSerializer.cs");
            var replacements = new Dictionary <string, string>();

            int              serverComponentCount   = 0;
            bool             needsLinkedEntityGroup = false;
            HashSet <string> imports = new HashSet <string>();

            imports.Add("Unity.Entities");
            imports.Add("Unity.Collections");
            imports.Add("Unity.NetCode");
            for (int comp = 0; comp < ghostInfo.Components.Length; ++comp)
            {
                var entityIndex = ghostInfo.Components[comp].entityIndex;
                if (!ghostInfo.Components[comp].server)
                {
                    continue;
                }
                imports.Add(ghostInfo.Components[comp].NamespaceName);
                var componentTypeName = GetShortName(ghostInfo.Components[comp]);
                replacements.Clear();
                replacements.Add("GHOST_COMPONENT_TYPE_NAME", componentTypeName);
                replacements.Add("GHOST_COMPONENT_TYPE", ghostInfo.Components[comp].ShortName.Replace("+", "."));
                replacements.Add("GHOST_ENTITY_INDEX", entityIndex.ToString());
                if (entityIndex == 0)
                {
                    ++serverComponentCount;
                    codeGen.GenerateFragment("GHOST_COMPONENT_TYPE", replacements);
                    codeGen.GenerateFragment("GHOST_ASSIGN_COMPONENT_TYPE", replacements);
                }

                if (ghostInfo.Components[comp].fields.Length > 0)
                {
                    if (entityIndex == 0)
                    {
                        codeGen.GenerateFragment("GHOST_COMPONENT_TYPE_DATA", replacements);
                        codeGen.GenerateFragment("GHOST_ASSIGN_COMPONENT_TYPE_DATA", replacements);
                        codeGen.GenerateFragment("GHOST_ASSIGN_CHUNK_ARRAY", replacements);
                    }
                    else
                    {
                        needsLinkedEntityGroup = true;
                        codeGen.GenerateFragment("GHOST_COMPONENT_TYPE_CHILD_DATA", replacements);
                        codeGen.GenerateFragment("GHOST_ASSIGN_COMPONENT_TYPE_CHILD_DATA", replacements);
                    }

                    for (int field = 0; field < ghostInfo.Components[comp].fields.Length; ++field)
                    {
                        replacements["GHOST_FIELD_NAME"] = ghostInfo.Components[comp].fields[field].name;
                        if (entityIndex == 0)
                        {
                            codeGen.GenerateFragment("GHOST_ASSIGN_SNAPSHOT", replacements);
                        }
                        else
                        {
                            codeGen.GenerateFragment("GHOST_ASSIGN_CHILD_SNAPSHOT", replacements);
                        }
                    }
                }
            }

            if (needsLinkedEntityGroup)
            {
                ++serverComponentCount;
                replacements.Clear();
                replacements.Add("GHOST_COMPONENT_TYPE_NAME", "LinkedEntityGroup");
                replacements.Add("GHOST_COMPONENT_TYPE", "LinkedEntityGroup");
                codeGen.GenerateFragment("GHOST_COMPONENT_TYPE", replacements);
                codeGen.GenerateFragment("GHOST_ASSIGN_COMPONENT_TYPE", replacements);

                codeGen.GenerateFragment("GHOST_BUFFER_COMPONENT_TYPE_DATA", replacements);
                codeGen.GenerateFragment("GHOST_ASSIGN_BUFFER_COMPONENT_TYPE_DATA", replacements);
                codeGen.GenerateFragment("GHOST_ASSIGN_CHUNK_BUFFER_ARRAY", replacements);
            }

            replacements.Clear();
            foreach (var ns in imports)
            {
                if (ns != null && ns != "")
                {
                    replacements["GHOST_USING"] = ns;
                    codeGen.GenerateFragment("GHOST_USING_STATEMENT", replacements);
                }
            }

            replacements.Clear();
            replacements.Add("GHOST_NAME", ghostInfo.name);
            replacements.Add("GHOST_IMPORTANCE", ghostInfo.Importance);
            replacements.Add("GHOST_COMPONENT_COUNT", serverComponentCount.ToString());
            codeGen.GenerateFile(assetPath, ghostInfo.RootPath, ghostInfo.SerializerPath, replacements, batch);
        }
Esempio n. 9
0
        static void GenerateSnapshotData(GhostAuthoringComponent ghostInfo, string ownerField, string assetPath, GhostCodeGen.Batch batch)
        {
            var codeGen      = new GhostCodeGen("Packages/com.unity.netcode/Editor/CodeGenTemplates/GhostSnapshotData.cs");
            var replacements = new Dictionary <string, string>();

            var typeProviders = new List <GhostSnapshotValue>();

            typeProviders.AddRange(GhostSnapshotValue.GameSpecificTypes);
            typeProviders.AddRange(GhostSnapshotValue.DefaultTypes);
            var typeCodeGenCache = new Dictionary <string, GhostCodeGen>();

            HashSet <string> imports = new HashSet <string>();

            imports.Add("Unity.Mathematics");
            bool hasTypeSpecificFields    = false;
            bool hasReadWritePredicted    = false;
            bool hasReadWriteInterpolated = false;

            if (ghostInfo.DefaultClientInstantiationType == GhostAuthoringComponent.ClientInstantionType.OwnerPredicted)
            {
                for (int comp = 0; comp < ghostInfo.Components.Length; ++comp)
                {
                    if (ghostInfo.Components[comp].server &&
                        ghostInfo.Components[comp].fields.Length > 0 &&
                        ghostInfo.Components[comp].sendDataTo != GhostAuthoringComponent.ClientSendType.All)
                    {
                        hasTypeSpecificFields = true;
                    }
                }
            }

            replacements.Add("GHOST_OWNER_FIELD", ownerField);
            if (hasTypeSpecificFields)
            {
                codeGen.GenerateFragment("GHOST_READ_IS_PREDICTED", replacements);
                codeGen.GenerateFragment("GHOST_WRITE_IS_PREDICTED", replacements);
            }

            int changeMaskIndex = 0;

            for (int comp = 0; comp < ghostInfo.Components.Length; ++comp)
            {
                if (!ghostInfo.Components[comp].server)
                {
                    continue;
                }
                for (int field = 0; field < ghostInfo.Components[comp].fields.Length; ++field)
                {
                    bool processed = false;
                    foreach (var value in typeProviders)
                    {
                        if (value.CanProcess(ghostInfo.Components[comp].fields[field].Field,
                                             ghostInfo.Components[comp].name,
                                             ghostInfo.Components[comp].fields[field].name))
                        {
                            var currentChangeMask = changeMaskIndex;
                            value.AddImports(imports);
                            var quantization  = ghostInfo.Components[comp].fields[field].quantization;
                            var shortName     = GetShortName(ghostInfo.Components[comp]);
                            var fullFieldName = shortName + ghostInfo.Components[comp].fields[field].name;

                            var typeCodeGenPath = value.GetTemplatePath(quantization);
                            if (!typeCodeGenCache.TryGetValue(typeCodeGenPath, out var typeCodeGen))
                            {
                                typeCodeGen = new GhostCodeGen(typeCodeGenPath);
                                typeCodeGenCache.Add(typeCodeGenPath, typeCodeGen);
                            }
                            replacements.Clear();
                            replacements.Add("GHOST_FIELD_NAME", fullFieldName);
                            replacements.Add("GHOST_FIELD_TYPE_NAME", GetFieldTypeName(ghostInfo.Components[comp].fields[field].Field.FieldType));
                            if (quantization > 0)
                            {
                                replacements.Add("GHOST_QUANTIZE_SCALE", quantization.ToString());
                                replacements.Add("GHOST_DEQUANTIZE_SCALE", $"{(1.0f / quantization).ToString(CultureInfo.InvariantCulture)}f");
                            }
                            replacements.Add("GHOST_MASK_BATCH", (currentChangeMask / 32).ToString());
                            replacements.Add("GHOST_MASK_INDEX", (currentChangeMask % 32).ToString());

                            typeCodeGen.GenerateFragment("GHOST_FIELD", replacements, codeGen);
                            typeCodeGen.GenerateFragment("GHOST_FIELD_GET_SET", replacements, codeGen);
                            typeCodeGen.GenerateFragment("GHOST_PREDICT", replacements, codeGen);
                            if (currentChangeMask % 32 == 0)
                            {
                                typeCodeGen.GenerateFragment("GHOST_CALCULATE_CHANGE_MASK_ZERO", replacements, codeGen, "GHOST_CALCULATE_CHANGE_MASK");
                            }
                            else
                            {
                                typeCodeGen.GenerateFragment("GHOST_CALCULATE_CHANGE_MASK", replacements, codeGen);
                            }

                            if (ghostInfo.Components[comp].fields[field].interpolate)
                            {
                                typeCodeGen.GenerateFragment("GHOST_INTERPOLATE", replacements, codeGen);
                            }

                            if (ghostInfo.Components[comp].server &&
                                ghostInfo.Components[comp].fields.Length > 0 &&
                                ghostInfo.Components[comp].sendDataTo == GhostAuthoringComponent.ClientSendType.Predicted)
                            {
                                if (!hasReadWritePredicted)
                                {
                                    codeGen.GenerateFragment("GHOST_BEGIN_READ_PREDICTED", replacements);
                                    codeGen.GenerateFragment("GHOST_END_READ_PREDICTED", replacements);
                                    codeGen.GenerateFragment("GHOST_BEGIN_WRITE_PREDICTED", replacements);
                                    codeGen.GenerateFragment("GHOST_END_WRITE_PREDICTED", replacements);
                                    hasReadWritePredicted = true;
                                }
                                typeCodeGen.GenerateFragment("GHOST_READ", replacements, codeGen, "GHOST_READ_PREDICTED", "    ");
                                typeCodeGen.GenerateFragment("GHOST_WRITE", replacements, codeGen, "GHOST_WRITE_PREDICTED", "    ");
                            }
                            else if (ghostInfo.Components[comp].server &&
                                     ghostInfo.Components[comp].fields.Length > 0 &&
                                     ghostInfo.Components[comp].sendDataTo == GhostAuthoringComponent.ClientSendType.Interpolated)
                            {
                                if (!hasReadWriteInterpolated)
                                {
                                    codeGen.GenerateFragment("GHOST_BEGIN_READ_INTERPOLATED", replacements);
                                    codeGen.GenerateFragment("GHOST_END_READ_INTERPOLATED", replacements);
                                    codeGen.GenerateFragment("GHOST_BEGIN_WRITE_INTERPOLATED", replacements);
                                    codeGen.GenerateFragment("GHOST_END_WRITE_INTERPOLATED", replacements);
                                    hasReadWriteInterpolated = true;
                                }
                                typeCodeGen.GenerateFragment("GHOST_READ", replacements, codeGen, "GHOST_READ_INTERPOLATED", "    ");
                                typeCodeGen.GenerateFragment("GHOST_WRITE", replacements, codeGen, "GHOST_WRITE_INTERPOLATED", "    ");
                            }
                            else
                            {
                                typeCodeGen.GenerateFragment("GHOST_READ", replacements, codeGen);
                                typeCodeGen.GenerateFragment("GHOST_WRITE", replacements, codeGen);
                            }
                            ++changeMaskIndex;

                            processed = true;
                            break;
                        }
                    }

                    if (!processed)
                    {
                        Debug.LogError("Unhandled type " + ghostInfo.Components[comp].fields[field].Field.FieldType);
                    }
                }
            }

            var numMasks = (changeMaskIndex + 31) / 32;

            for (int i = 0; i < numMasks; ++i)
            {
                replacements["GHOST_MASK_BATCH"] = i.ToString();
                codeGen.GenerateFragment("GHOST_CHANGE_MASK", replacements);
                codeGen.GenerateFragment("GHOST_WRITE_CHANGE_MASK", replacements);
                codeGen.GenerateFragment("GHOST_READ_CHANGE_MASK", replacements);
            }

            replacements.Clear();
            foreach (var ns in imports)
            {
                if (ns != null && ns != "")
                {
                    replacements["GHOST_USING"] = ns;
                    codeGen.GenerateFragment("GHOST_USING_STATEMENT", replacements);
                }
            }

            replacements.Clear();
            replacements.Add("GHOST_NAME", ghostInfo.name);
            codeGen.GenerateFile(assetPath, ghostInfo.RootPath, ghostInfo.SnapshotDataPath, replacements, batch);
        }
Esempio n. 10
0
        public static GhostCodeGen.Status GenerateGhost(GhostAuthoringComponent ghostInfo, bool testOnly = false)
        {
            var tempWorld = new World("GhostEnsureECSLoaded");

            tempWorld.Dispose();

            var allTypes   = TypeManager.GetAllTypes();
            var typeLookup = new Dictionary <string, Type>();

            foreach (var compType in allTypes)
            {
                if (compType.Type != null)
                {
                    typeLookup.Add(compType.Type.FullName, compType.Type);
                }
            }

            string ownerField = "";

            // Update type of all fields
            for (int comp = 0; comp < ghostInfo.Components.Length; ++comp)
            {
                if (!typeLookup.TryGetValue(ghostInfo.Components[comp].name, out var componentType))
                {
                    Debug.LogError($"Could not find the type {ghostInfo.Components[comp].name}");
                    return(GhostCodeGen.Status.Failed);
                }
                ghostInfo.Components[comp].NamespaceName = componentType.Namespace;
                ghostInfo.Components[comp].ShortName     = (String.IsNullOrEmpty(componentType.Namespace))
                    ? componentType.FullName
                    : componentType.FullName.Substring(componentType.Namespace.Length + 1);
                for (int field = 0; field < ghostInfo.Components[comp].fields.Length; ++field)
                {
                    var fieldInfo = componentType.GetField(ghostInfo.Components[comp].fields[field].name);
                    if (fieldInfo == null)
                    {
                        Debug.LogError("Could not find field: " + ghostInfo.Components[comp].fields[field].name +
                                       " in componentType: " + ghostInfo.Components[comp].name);
                        return(GhostCodeGen.Status.Failed);
                    }

                    ghostInfo.Components[comp].fields[field].Field = fieldInfo;

                    if (ghostInfo.DefaultClientInstantiationType ==
                        GhostAuthoringComponent.ClientInstantionType.OwnerPredicted &&
                        ghostInfo.PredictingPlayerNetworkId == ghostInfo.Components[comp].name + "." +
                        ghostInfo.Components[comp].fields[field].name)
                    {
                        ownerField = GetShortName(ghostInfo.Components[comp]) +
                                     ghostInfo.Components[comp].fields[field].name;
                    }
                }
            }

            var assetPath = GhostCodeGen.GetPrefabAssetPath(ghostInfo.gameObject);

            var batch = new GhostCodeGen.Batch();

            GenerateSnapshotData(ghostInfo, ownerField, assetPath, batch);
            GenerateSerializer(ghostInfo, assetPath, batch);
            GenerateUpdateSystem(ghostInfo, ownerField, assetPath, batch);
            var didWrite = batch.Flush(testOnly);

            AssetDatabase.Refresh();
            return(didWrite ? GhostCodeGen.Status.Ok : GhostCodeGen.Status.NotModified);
        }
Esempio n. 11
0
        static void AddToComponentList(GhostAuthoringComponent self,
                                       List <GhostAuthoringComponent.GhostComponent> newComponents, Dictionary <string, int> toDelete,
                                       World tempWorld, Entity convertedEntity, int entityIndex)
        {
            var typeProviders = new List <GhostSnapshotValue>();

            typeProviders.AddRange(GhostSnapshotValue.GameSpecificTypes);
            typeProviders.AddRange(GhostSnapshotValue.DefaultTypes);

            var compTypes = tempWorld.EntityManager.GetComponentTypes(convertedEntity);

            compTypes.Sort(default(ComponentNameComparer));
            for (int i = 0; i < compTypes.Length; ++i)
            {
                var managedType = compTypes[i].GetManagedType();
                if (managedType == typeof(Prefab) || managedType == typeof(LinkedEntityGroup))
                {
                    continue;
                }
                GhostAuthoringComponent.GhostComponent newComponent;
                if (GhostDefaultOverrides.TryGetValue(managedType.FullName, out newComponent))
                {
                    newComponent.fields = (GhostAuthoringComponent.GhostComponentField[])newComponent.fields.Clone();
                }
                else
                {
                    var fields = new List <GhostAuthoringComponent.GhostComponentField>();
                    foreach (var componentField in managedType.GetFields())
                    {
                        var attr = componentField.GetCustomAttributes <GhostDefaultFieldAttribute>().ToArray();
                        if (attr.Length > 0)
                        {
                            bool valid = true;
                            foreach (var valueType in typeProviders)
                            {
                                if (valueType.CanProcess(componentField, managedType.FullName,
                                                         componentField.Name))
                                {
                                    if (attr[0].Quantization < 0 && valueType.SupportsQuantization)
                                    {
                                        Debug.LogError(String.Format(
                                                           "{0}.{1} is of type {2} which requires quantization factor to be specified - ignoring field",
                                                           managedType.FullName, componentField.Name, componentField.FieldType));
                                        valid = false;
                                    }

                                    if (attr[0].Quantization > 1 && !valueType.SupportsQuantization)
                                    {
                                        Debug.LogError(String.Format(
                                                           "{0}.{1} is of type {2} which does not support quantization - ignoring field",
                                                           managedType.FullName, componentField.Name, componentField.FieldType));
                                        valid = false;
                                    }

                                    break;
                                }
                            }

                            if (valid)
                            {
                                // If type requires quantization not specifying quantization is an error (log + ignore field)
                                fields.Add(new GhostAuthoringComponent.GhostComponentField
                                {
                                    name         = componentField.Name,
                                    quantization = attr[0].Quantization,
                                    interpolate  = attr[0].Interpolate
                                });
                            }
                        }
                    }

                    newComponent = new GhostAuthoringComponent.GhostComponent
                    {
                        name = managedType.FullName,
                        interpolatedClient = true,
                        predictedClient    = true,
                        server             = true,
                        fields             = fields.ToArray(),
                        manualFieldList    = false
                    };
                    var compAttr = managedType.GetCustomAttributes <GhostDefaultComponentAttribute>().ToArray();
                    if (compAttr.Length > 0)
                    {
                        newComponent.server             = (compAttr[0].TargetType & GhostDefaultComponentAttribute.Type.Server) != 0;
                        newComponent.interpolatedClient =
                            (compAttr[0].TargetType & GhostDefaultComponentAttribute.Type.InterpolatedClient) != 0;
                        newComponent.predictedClient =
                            (compAttr[0].TargetType & GhostDefaultComponentAttribute.Type.PredictedClient) != 0;
                    }
                }

                if (toDelete.TryGetValue(entityIndex + managedType.FullName, out var compIdx))
                {
                    var fields = newComponent.fields;
                    newComponent = self.Components[compIdx];
                    if (!self.Components[compIdx].manualFieldList)
                    {
                        newComponent.fields = fields;
                    }

                    toDelete.Remove(entityIndex + managedType.FullName);
                }

                if (entityIndex > 0)
                {
                    // Stripping components on child entities is not supported
                    newComponent.server             = true;
                    newComponent.interpolatedClient = true;
                    newComponent.predictedClient    = true;
                }
                newComponent.entityIndex = entityIndex;
                newComponents.Add(newComponent);
            }
        }
Esempio n. 12
0
    void GenerateUpdateSystem(GhostAuthoringComponent ghostInfo)
    {
        var ghostInterpolatedComponentRefs  = "";
        var ghostPredictedComponentRefs     = "";
        var ghostInterpolatedComponentTypes = "";
        var ghostPredictedComponentTypes    = "";
        var ghostInterpolatedAssignments    = "";
        var ghostPredictedAssignments       = "";

        for (int comp = 0; comp < ghostInfo.Components.Length; ++comp)
        {
            if (ghostInfo.Components[comp].fields.Length > 0)
            {
                if (ghostInfo.Components[comp].interpolatedClient)
                {
                    if (ghostInterpolatedComponentTypes != "")
                    {
                        ghostInterpolatedComponentTypes += ", ";
                    }

                    ghostInterpolatedComponentTypes += ghostInfo.Components[comp].name;
                    ghostInterpolatedComponentRefs  +=
                        k_GhostUpdateComponentRefTemplate.Replace("$(GHOSTCOMPONENT)",
                                                                  ghostInfo.Components[comp].name);
                    for (int field = 0; field < ghostInfo.Components[comp].fields.Length; ++field)
                    {
                        ghostInterpolatedAssignments +=
                            k_GhostUpdateAssignTemplate.Replace("$(GHOSTCOMPONENT)",
                                                                ghostInfo.Components[comp].name)
                            .Replace("$(GHOSTFIELD)",
                                     ghostInfo.Components[comp].fields[field].name);
                    }
                }
                if (ghostInfo.Components[comp].predictedClient)
                {
                    if (ghostPredictedComponentTypes != "")
                    {
                        ghostPredictedComponentTypes += ", ";
                    }

                    ghostPredictedComponentTypes += ghostInfo.Components[comp].name;
                    ghostPredictedComponentRefs  +=
                        k_GhostUpdateComponentRefTemplate.Replace("$(GHOSTCOMPONENT)",
                                                                  ghostInfo.Components[comp].name);
                    for (int field = 0; field < ghostInfo.Components[comp].fields.Length; ++field)
                    {
                        ghostPredictedAssignments +=
                            k_GhostUpdateAssignTemplate.Replace("$(GHOSTCOMPONENT)",
                                                                ghostInfo.Components[comp].name)
                            .Replace("$(GHOSTFIELD)",
                                     ghostInfo.Components[comp].fields[field].name);
                    }
                }
            }
        }
        var updateData = k_GhostUpdateSystemTemplate
                         .Replace("$(GHOSTNAME)", target.name)
                         .Replace("$(GHOSTINTERPOLATEDCOMPONENTREFS)", ghostInterpolatedComponentRefs)
                         .Replace("$(GHOSTPREDICTEDCOMPONENTREFS)", ghostPredictedComponentRefs)
                         .Replace("$(GHOSTINTERPOLATEDCOMPONENTTYPES)", ghostInterpolatedComponentTypes)
                         .Replace("$(GHOSTPREDICTEDCOMPONENTTYPES)", ghostPredictedComponentTypes)
                         .Replace("$(GHOSTINTERPOLATEDASSIGNMENTS)", ghostInterpolatedAssignments)
                         .Replace("$(GHOSTPREDICTEDASSIGNMENTS)", ghostPredictedAssignments);

        File.WriteAllText(Path.Combine(assetPath, ghostInfo.UpdateSystemPath), updateData);
    }
Esempio n. 13
0
    void GenerateSnapshotData(GhostAuthoringComponent ghostInfo)
    {
        var fields        = "";
        var fieldsGetSet  = "";
        var predict       = "";
        var read          = "";
        var write         = "";
        var interpolate   = "";
        var typeProviders = new List <GhostSnapshotValue>();

        typeProviders.AddRange(GhostSnapshotValue.GameSpecificTypes);

        typeProviders.Add(new GhostSnapshotValueQuaternion());
        typeProviders.Add(new GhostSnapshotValueFloat());
        typeProviders.Add(new GhostSnapshotValueFloat2());
        typeProviders.Add(new GhostSnapshotValueFloat3());
        typeProviders.Add(new GhostSnapshotValueFloat4());
        typeProviders.Add(new GhostSnapshotValueInt());
        typeProviders.Add(new GhostSnapshotValueUInt());
        for (int comp = 0; comp < ghostInfo.Components.Length; ++comp)
        {
            for (int field = 0; field < ghostInfo.Components[comp].fields.Length; ++field)
            {
                bool processed = false;
                foreach (var value in typeProviders)
                {
                    if (value.CanProcess(ghostInfo.Components[comp].fields[field].DataType,
                                         ghostInfo.Components[comp].name,
                                         ghostInfo.Components[comp].fields[field].name))
                    {
                        fields += value.GenerateMembers(ghostInfo.Components[comp].name,
                                                        ghostInfo.Components[comp].fields[field].name);
                        fieldsGetSet += value.GenerateGetSet(ghostInfo.Components[comp].name,
                                                             ghostInfo.Components[comp].fields[field].name,
                                                             ghostInfo.Components[comp].fields[field].quantization);
                        predict += value.GeneratePredict(ghostInfo.Components[comp].name,
                                                         ghostInfo.Components[comp].fields[field].name);
                        read += value.GenerateRead(ghostInfo.Components[comp].name,
                                                   ghostInfo.Components[comp].fields[field].name);
                        write += value.GenerateWrite(ghostInfo.Components[comp].name,
                                                     ghostInfo.Components[comp].fields[field].name);
                        if (ghostInfo.Components[comp].fields[field].interpolate)
                        {
                            interpolate += value.GenerateInterpolate(ghostInfo.Components[comp].name,
                                                                     ghostInfo.Components[comp].fields[field].name);
                        }

                        processed = true;
                        break;
                    }
                }
                if (!processed)
                {
                    Debug.LogError("Unhandled type " + ghostInfo.Components[comp].fields[field].DataType);
                }
            }
        }

        var snapshotData = k_SnapshotDataTemplate
                           .Replace("$(GHOSTNAME)", target.name)
                           .Replace("$(GHOSTFIELDS)", fields)
                           .Replace("$(GHOSTFIELDSGETSET)", fieldsGetSet)
                           .Replace("$(GHOSTPREDICT)", predict)
                           .Replace("$(GHOSTREAD)", read)
                           .Replace("$(GHOSTWRITE)", write)
                           .Replace("$(GHOSTINTERPOLATE)", interpolate);


        File.WriteAllText(Path.Combine(assetPath, ghostInfo.SnapshotDataPath), snapshotData);
    }