コード例 #1
0
        private void GenerateRegistrationSystem(Context context)
        {
            //Generate the ghost registration

            var regTemplate = "Packages/com.unity.netcode/Editor/CodeGenTemplates/GhostComponentSerializerRegistrationSystem.cs";

            if (!context.typeCodeGenCache.TryGetValue(regTemplate, out var registrationSystemCodeGen))
            {
                registrationSystemCodeGen = new GhostCodeGen(regTemplate);

                context.typeCodeGenCache.Add(regTemplate, registrationSystemCodeGen);
            }
            registrationSystemCodeGen = registrationSystemCodeGen.Clone();
            var replacements = new Dictionary <string, string>();

            foreach (var t in context.generatedTypes)
            {
                replacements["GHOST_NAME"] = t;
                registrationSystemCodeGen.GenerateFragment("GHOST_COMPONENT_LIST", replacements);
            }
            replacements.Clear();
            replacements["GHOST_USING"] = context.generatedNs;
            registrationSystemCodeGen.GenerateFragment("GHOST_USING_STATEMENT", replacements);

            replacements.Clear();
            replacements.Add("GHOST_NAMESPACE", context.generatedNs);
            registrationSystemCodeGen.GenerateFile("", context.outputFolder,
                                                   $"GhostComponentSerializerCollection.cs", replacements, context.batch);
        }
コード例 #2
0
        public CommandGenerator(CodeGenerator.Context context, Type t)
        {
            CommandType = t;
            var template = t == Type.Rpc ?
                           "Packages/com.unity.netcode/Editor/CodeGenTemplates/RpcCommandSerializer.cs" :
                           "Packages/com.unity.netcode/Editor/CodeGenTemplates/CommandDataSerializer.cs";

            if (!context.typeCodeGenCache.TryGetValue(template, out var generator))
            {
                generator = new GhostCodeGen(template);

                context.typeCodeGenCache.Add(template, generator);
            }
            m_CommandGenerator = generator.Clone();
        }
コード例 #3
0
        public GhostCodeGen Clone()
        {
            var codeGen = new GhostCodeGen();

            codeGen.m_FileTemplate   = m_FileTemplate;
            codeGen.m_HeaderTemplate = m_HeaderTemplate;
            codeGen.Replacements     = new Dictionary <string, string>();
            codeGen.m_Fragments      = new Dictionary <string, FragmentData>();
            foreach (var value in m_Fragments)
            {
                codeGen.m_Fragments.Add(value.Key, new FragmentData {
                    Template = value.Value.Template, Content = ""
                });
            }
            return(codeGen);
        }
コード例 #4
0
        public void Append(GhostCodeGen target)
        {
            if (target == null)
            {
                target = this;
            }

            foreach (var fragment in m_Fragments)
            {
                if (!target.m_Fragments.ContainsKey($"{fragment.Key}"))
                {
                    Debug.LogWarning($"Target CodeGen is missing fragment: {fragment.Key}");
                    continue;
                }
                target.m_Fragments[$"{fragment.Key}"].Content += m_Fragments[$"{fragment.Key}"].Content;
            }
        }
コード例 #5
0
        public TypeGenerator(CodeGenerator.Context context)
        {
            var template = "Packages/com.unity.netcode/Editor/CodeGenTemplates/GhostComponentSerializer.cs";

            if (!context.typeCodeGenCache.TryGetValue(template, out var generator))
            {
                generator = new GhostCodeGen(template);

                context.typeCodeGenCache.Add(template, generator);
            }
            m_TargetGenerator = generator.Clone();
            foreach (var frag in k_OverridableFragments.Cast <string>())
            {
                if (!m_OverridableFragmentsList.Contains(frag))
                {
                    m_OverridableFragmentsList += " " + frag;
                }
            }
            ;
        }
コード例 #6
0
        public void GenerateFields(CodeGenerator.Context context, string parent = null)
        {
            if (m_Template == null)
            {
                return;
            }

            if (!context.typeCodeGenCache.TryGetValue(m_Template.TemplatePath + m_Template.TemplateOverridePath,
                                                      out var generator))
            {
                generator = new GhostCodeGen(m_Template.TemplatePath);

                if (!string.IsNullOrEmpty(m_Template.TemplateOverridePath))
                {
                    generator.AddTemplateOverrides(m_Template.TemplateOverridePath);
                }

                context.typeCodeGenCache.Add(m_Template.TemplatePath + m_Template.TemplateOverridePath, generator);
            }
            var fieldName = string.IsNullOrEmpty(parent)
                ? m_TypeInformation.FieldName
                : $"{parent}.{m_TypeInformation.FieldName}";

            generator = generator.Clone();
            generator.Replacements.Add("COMMAND_FIELD_NAME", fieldName);
            generator.Replacements.Add("COMMAND_FIELD_TYPE_NAME", m_TypeInformation.Type.GetFieldTypeName());

            generator.GenerateFragment("COMMAND_READ", generator.Replacements, m_CommandGenerator);
            generator.GenerateFragment("COMMAND_WRITE", generator.Replacements, m_CommandGenerator);

            if (CommandType != CommandGenerator.Type.Rpc)
            {
                generator.GenerateFragment("COMMAND_READ_PACKED", generator.Replacements, m_CommandGenerator);
                generator.GenerateFragment("COMMAND_WRITE_PACKED", generator.Replacements, m_CommandGenerator);
            }

            if (m_TypeInformation.Type.Scope != null)
            {
                context.collectionAssemblies.Add(m_TypeInformation.Type.Scope.Name);
            }
        }
コード例 #7
0
        public void AppendFragment(string fragment,
                                   GhostCodeGen target, string targetFragment = null, string extraIndent = null)
        {
            if (target == null)
            {
                target = this;
            }
            if (targetFragment == null)
            {
                targetFragment = fragment;
            }
            if (!m_Fragments.ContainsKey($"__{fragment}__"))
            {
                throw new InvalidOperationException($"{fragment} is not a valid fragment for the given template");
            }
            if (!target.m_Fragments.ContainsKey($"__{targetFragment}__"))
            {
                throw new InvalidOperationException($"{targetFragment} is not a valid fragment for the given template");
            }

            target.m_Fragments[$"__{targetFragment}__"].Content += m_Fragments[$"__{fragment}__"].Content;
        }
コード例 #8
0
        public Dictionary <string, GhostCodeGen.FragmentData> GenerateCompositeOverrides(CodeGenerator.Context context, string parent = null)
        {
            var fragments = new Dictionary <string, GhostCodeGen.FragmentData>();

            if (m_Template == null || string.IsNullOrEmpty(m_Template.TemplateOverridePath))
            {
                return(null);
            }

            var quantization = m_TypeInformation.Attribute.quantization;
            var interpolate  = m_TypeInformation.Attribute.smoothing > 0;

            if (!context.typeCodeGenCache.TryGetValue(m_Template.TemplateOverridePath,
                                                      out var generator))
            {
                generator = new GhostCodeGen(m_Template.TemplateOverridePath);
                context.typeCodeGenCache.Add(m_Template.TemplateOverridePath, generator);
            }

            generator = generator.Clone();

            // Prefix and Variable Replacements
            var reference = string.IsNullOrEmpty(parent)
                ? m_TypeInformation.FieldName : $"{parent}.{m_TypeInformation.FieldName}";
            var name = reference.Replace('.', '_');

            generator.Replacements.Add("GHOST_FIELD_NAME", $"{name}");
            generator.Replacements.Add("GHOST_FIELD_REFERENCE", $"{reference}");
            generator.Replacements.Add("GHOST_FIELD_TYPE_NAME", m_TypeInformation.Type.GetFieldTypeName());

            if (quantization > 0)
            {
                generator.Replacements.Add("GHOST_QUANTIZE_SCALE", quantization.ToString());
                generator.Replacements.Add("GHOST_DEQUANTIZE_SCALE",
                                           $"{(1.0f / quantization).ToString(CultureInfo.InvariantCulture)}f");
            }
            float maxSmoothingDistSq  = m_TypeInformation.Attribute.maxSmoothingDist * m_TypeInformation.Attribute.maxSmoothingDist;
            bool  enableExtrapolation = m_TypeInformation.Attribute.smoothing == (uint)TypeAttribute.AttributeFlags.InterpolatedAndExtrapolated;

            generator.Replacements.Add("GHOST_MAX_INTERPOLATION_DISTSQ", maxSmoothingDistSq.ToString(CultureInfo.InvariantCulture));

            // Type Info
            if (generator.GenerateFragment("GHOST_FIELD", generator.Replacements, m_TargetGenerator, null, null, true))
            {
                fragments.Add("GHOST_FIELD", m_TargetGenerator.Fragments["__GHOST_FIELD__"]);
            }
            // CopyToSnapshot
            if (generator.GenerateFragment("GHOST_COPY_TO_SNAPSHOT", generator.Replacements, m_TargetGenerator, null, null, true))
            {
                fragments.Add("GHOST_COPY_TO_SNAPSHOT", m_TargetGenerator.Fragments["__GHOST_COPY_TO_SNAPSHOT__"]);
            }

            // CopyFromSnapshot
            if (interpolate)
            {
                if (generator.HasFragment("GHOST_COPY_FROM_SNAPSHOT_INTERPOLATE"))
                {
                    m_TargetGenerator.GenerateFragment(enableExtrapolation ? "GHOST_COPY_FROM_SNAPSHOT_ENABLE_EXTRAPOLATION" : "GHOST_COPY_FROM_SNAPSHOT_DISABLE_EXTRAPOLATION",
                                                       generator.Replacements, m_TargetGenerator, "GHOST_COPY_FROM_SNAPSHOT");
                    // The setup section is optional, so do not generate error if it is not present
                    generator.GenerateFragment("GHOST_COPY_FROM_SNAPSHOT_INTERPOLATE_SETUP", generator.Replacements, m_TargetGenerator,
                                               "GHOST_COPY_FROM_SNAPSHOT", null, true);
                    // only generate max distance checks if clamp is enabled
                    if (maxSmoothingDistSq > 0)
                    {
                        generator.GenerateFragment("GHOST_COPY_FROM_SNAPSHOT_INTERPOLATE_DISTSQ", generator.Replacements, m_TargetGenerator,
                                                   "GHOST_COPY_FROM_SNAPSHOT");
                        m_TargetGenerator.GenerateFragment("GHOST_COPY_FROM_SNAPSHOT_INTERPOLATE_CLAMP_MAX", generator.Replacements, m_TargetGenerator,
                                                           "GHOST_COPY_FROM_SNAPSHOT");
                    }
                    generator.GenerateFragment("GHOST_COPY_FROM_SNAPSHOT_INTERPOLATE",
                                               generator.Replacements, m_TargetGenerator, "GHOST_COPY_FROM_SNAPSHOT");
                    fragments.Add("GHOST_COPY_FROM_SNAPSHOT", generator.Fragments["__GHOST_COPY_FROM_SNAPSHOT__"]);
                    fragments.Add("GHOST_COPY_FROM_SNAPSHOT_INTERPOLATE", generator.Fragments["__GHOST_COPY_FROM_SNAPSHOT_INTERPOLATE__"]);
                }
            }
            else
            {
                if (generator.GenerateFragment("GHOST_COPY_FROM_SNAPSHOT",
                                               generator.Replacements, m_TargetGenerator, "GHOST_COPY_FROM_SNAPSHOT", null, true))
                {
                    fragments.Add("GHOST_COPY_FROM_SNAPSHOT", generator.Fragments["__GHOST_COPY_FROM_SNAPSHOT__"]);
                    fragments.Add("GHOST_COPY_FROM_SNAPSHOT_INTERPOLATE", generator.Fragments["__GHOST_COPY_FROM_SNAPSHOT_INTERPOLATE__"]);
                }
            }
            // RestoreFromBackup
            if (generator.GenerateFragment("GHOST_RESTORE_FROM_BACKUP", generator.Replacements, m_TargetGenerator, null, null, true))
            {
                fragments.Add("GHOST_RESTORE_FROM_BACKUP", m_TargetGenerator.Fragments["__GHOST_RESTORE_FROM_BACKUP__"]);
            }
            // PredictDelta
            if (generator.GenerateFragment("GHOST_PREDICT", generator.Replacements, m_TargetGenerator, null, null, true))
            {
                fragments.Add("GHOST_PREDICT", m_TargetGenerator.Fragments["__GHOST_PREDICT__"]);
            }

            // ReportPredictionError
            if (generator.GenerateFragment("GHOST_REPORT_PREDICTION_ERROR", generator.Replacements, m_TargetGenerator, null, null, true))
            {
                fragments.Add("GHOST_REPORT_PREDICTION_ERROR", m_TargetGenerator.Fragments["__GHOST_REPORT_PREDICTION_ERROR__"]);
            }
            // GetPredictionErrorName
            if (generator.GenerateFragment("GHOST_GET_PREDICTION_ERROR_NAME", generator.Replacements, m_TargetGenerator, null, null, true))
            {
                fragments.Add("GHOST_GET_PREDICTION_ERROR_NAME", m_TargetGenerator.Fragments["__GHOST_GET_PREDICTION_ERROR_NAME__"]);
            }

            ValidateOverridableFragments(generator.Fragments);

            m_ActiveGenerator = generator;
            return(fragments);
        }
コード例 #9
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);
        }
コード例 #10
0
        public static GhostCodeGen.Status GenerateCollection(GhostCollectionAuthoringComponent collectionTarget, bool testOnly = false)
        {
            var serializerCodeGen   = new GhostCodeGen("Packages/com.unity.netcode/Editor/CodeGenTemplates/GhostSerializerCollection.cs");
            var deserializerCodeGen = new GhostCodeGen("Packages/com.unity.netcode/Editor/CodeGenTemplates/GhostDeserializerCollection.cs");

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

            int ghostCount = 0;
            var namePrefix = collectionTarget.NamePrefix;

            var localReplacements = new Dictionary <string, string>();

            for (int i = 0; i < collectionTarget.Ghosts.Count; ++i)
            {
                var ghost = collectionTarget.Ghosts[i];
                if (ghost.prefab != null && ghost.enabled)
                {
                    ++ghostCount;
                    var serializerTypeName = ghost.prefab.name + "GhostSerializer";
                    var snapshotTypeName   = ghost.prefab.name + "SnapshotData";
                    var spawnerTypeName    = ghost.prefab.name + "GhostSpawnSystem";

                    localReplacements.Clear();
                    localReplacements.Add("GHOST_SERIALIZER_TYPE", serializerTypeName);
                    localReplacements.Add("GHOST_SNAPSHOT_TYPE", snapshotTypeName);
                    localReplacements.Add("GHOST_SPAWNER_TYPE", spawnerTypeName);
                    localReplacements.Add("GHOST_SERIALIZER_INDEX", i.ToString());
                    localReplacements.Add("GHOST_COLLECTION_PREFIX", namePrefix);

                    serializerCodeGen.GenerateFragment("GHOST_SERIALIZER_INSTANCE", localReplacements);
                    deserializerCodeGen.GenerateFragment("GHOST_DESERIALIZER_INSTANCE", localReplacements);

                    serializerCodeGen.GenerateFragment("GHOST_SERIALIZER_NAME", localReplacements);
                    serializerCodeGen.GenerateFragment("GHOST_FIND_TYPE", localReplacements);
                    serializerCodeGen.GenerateFragment("GHOST_BEGIN_SERIALIZE", localReplacements);
                    serializerCodeGen.GenerateFragment("GHOST_CALCULATE_IMPORTANCE", localReplacements);
                    serializerCodeGen.GenerateFragment("GHOST_SNAPSHOT_SIZE", localReplacements);
                    serializerCodeGen.GenerateFragment("GHOST_INVOKE_SERIALIZE", localReplacements);

                    deserializerCodeGen.GenerateFragment("GHOST_SERIALIZER_NAME", localReplacements);
                    deserializerCodeGen.GenerateFragment("GHOST_INITIALIZE_DESERIALIZE", localReplacements);
                    deserializerCodeGen.GenerateFragment("GHOST_BEGIN_DESERIALIZE", localReplacements);
                    deserializerCodeGen.GenerateFragment("GHOST_INVOKE_DESERIALIZE", localReplacements);
                    deserializerCodeGen.GenerateFragment("GHOST_INVOKE_SPAWN", localReplacements);
                }
            }

            var replacements = new Dictionary <string, string>();

            replacements.Add("GHOST_COLLECTION_PREFIX", namePrefix);
            replacements.Add("GHOST_SYSTEM_PREFIX", namePrefix);
            replacements.Add("GHOST_SERIALIZER_COUNT", ghostCount.ToString());
            var batch = new GhostCodeGen.Batch();

            serializerCodeGen.GenerateFile(assetPath, "", collectionTarget.SerializerCollectionPath, replacements, batch);
            deserializerCodeGen.GenerateFile(assetPath, "", collectionTarget.DeserializerCollectionPath, replacements, batch);
            bool didWrite = batch.Flush(testOnly);

            AssetDatabase.Refresh();
            return(didWrite ? GhostCodeGen.Status.Ok : GhostCodeGen.Status.NotModified);
        }
コード例 #11
0
        private void GenerateAsmDefs(Context context, string assemblyGeneratedName)
        {
            var asmdefPath        = UnityEditor.Compilation.CompilationPipeline.GetAssemblyDefinitionFilePathFromAssemblyName(context.AssemblyName);
            var includePlatforms  = "";
            var excludePlatforms  = "";
            var defineConstraints = "";

            if (!string.IsNullOrEmpty(asmdefPath))
            {
                var assemblyDefinition = UnityEngine.JsonUtility.FromJson <GhostCompiler.UnityAssemblyDefinition>(System.IO.File.ReadAllText(asmdefPath));
                string EscapeStrings(string[] list)
                {
                    if (list == null)
                    {
                        return("");
                    }
                    for (var i = 0; i < list.Length; ++i)
                    {
                        list[i] = $"\"{list[i]}\"";
                    }
                    return(string.Join(",", list));
                }

                includePlatforms  = EscapeStrings(assemblyDefinition.includePlatforms);
                excludePlatforms  = EscapeStrings(assemblyDefinition.excludePlatforms);
                defineConstraints = EscapeStrings(assemblyDefinition.defineConstraints);

                foreach (var r in assemblyDefinition.references)
                {
                    context.collectionAssemblies.Add(r);
                }
            }

            //Remove unwanted references to basic assemblies
            context.collectionAssemblies.Remove("mscorlib");
            context.collectionAssemblies.Remove("netstandard");

            // Use guid references instead of assembly name references
            // Some references comes from the assembly which we are generating code for,
            // if those are guids and we add by name too we can get duplicate references
            var nonGuids = new List <string>();

            foreach (var asm in context.collectionAssemblies)
            {
                if (!asm.StartsWith("GUID:"))
                {
                    nonGuids.Add(asm);
                }
            }
            foreach (var nonGuid in nonGuids)
            {
                var path = UnityEditor.Compilation.CompilationPipeline.GetAssemblyDefinitionFilePathFromAssemblyName(nonGuid);
                if (path != null)
                {
                    var guid = UnityEditor.AssetDatabase.AssetPathToGUID(path);
                    if (!String.IsNullOrEmpty(guid))
                    {
                        context.collectionAssemblies.Remove(nonGuid);
                        context.collectionAssemblies.Add(UnityEditor.Compilation.CompilationPipeline.GUIDToAssemblyDefinitionReferenceGUID(guid));
                    }
                }
            }
            //Remove duplicate (already added)
            context.collectionAssemblies.Remove("Unity.Networking.Transport");
            var transportPath = UnityEditor.Compilation.CompilationPipeline.GetAssemblyDefinitionFilePathFromAssemblyName("Unity.Networking.Transport");

            if (transportPath != null)
            {
                var guid = UnityEditor.AssetDatabase.AssetPathToGUID(transportPath);
                if (!String.IsNullOrEmpty(guid))
                {
                    context.collectionAssemblies.Remove(UnityEditor.Compilation.CompilationPipeline.GUIDToAssemblyDefinitionReferenceGUID(guid));
                }
            }

            var replacements   = new Dictionary <string, string>();
            var asmdefTemplate = "Packages/com.unity.netcode/Editor/CodeGenTemplates/NetCode.Generated.asmdef.template";

            if (!context.typeCodeGenCache.TryGetValue(asmdefTemplate, out var asmdefCodeGen))
            {
                asmdefCodeGen = new GhostCodeGen(asmdefTemplate);

                context.typeCodeGenCache.Add(asmdefTemplate, asmdefCodeGen);
            }
            asmdefCodeGen = asmdefCodeGen.Clone();

            replacements.Add("ASSEMBLY_NAME", assemblyGeneratedName);
            asmdefCodeGen.GenerateFragment("GHOST_ASSEMBLY_NAME", replacements);
            foreach (var asm in context.collectionAssemblies)
            {
                replacements["GHOST_ASSEMBLY"] = asm;
                asmdefCodeGen.GenerateFragment("GHOST_ASSEMBLIES", replacements);
            }
            replacements.Add("GHOST_INCLUDE_PLATFORMS", includePlatforms);
            replacements.Add("GHOST_EXCLUDE_PLATFORMS", excludePlatforms);
            replacements.Add("GHOST_DEFINE_CONSTRAINTS", defineConstraints);
            asmdefCodeGen.GenerateFile("", context.outputFolder, $"{assemblyGeneratedName}.asmdef",
                                       replacements, context.batch);
        }
コード例 #12
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);
        }
コード例 #13
0
        public bool GenerateFragment(string fragment, Dictionary <string, string> replacements, GhostCodeGen target = null, string targetFragment = null, string extraIndent = null, bool allowMissingFragment = false)
        {
            if (target == null)
            {
                target = this;
            }
            if (targetFragment == null)
            {
                targetFragment = fragment;
            }
            if (!m_Fragments.ContainsKey($"__{fragment}__") && !allowMissingFragment)
            {
                throw new InvalidOperationException($"{fragment} is not a valid fragment for the given template");
            }
            if (!m_Fragments.ContainsKey($"__{fragment}__") && allowMissingFragment)
            {
                return(false);
            }
            if (!target.m_Fragments.ContainsKey($"__{targetFragment}__"))
            {
                throw new InvalidOperationException($"{targetFragment} is not a valid fragment for the given template");
            }
            var content = Replace(m_Fragments[$"__{fragment}__"].Template, replacements);

            if (extraIndent != null)
            {
                content = extraIndent + content.Replace("\n    ", $"\n    {extraIndent}");
            }

            Validate(content, fragment);
            target.m_Fragments[$"__{targetFragment}__"].Content += content;
            return(true);
        }
コード例 #14
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);
        }
コード例 #15
0
        public void GenerateFields(CodeGenerator.Context context, string parent = null, Dictionary <string, GhostCodeGen.FragmentData> overrides = null)
        {
            if (m_Template == null)
            {
                return;
            }

            var quantization = m_TypeInformation.Attribute.quantization;
            var interpolate  = m_TypeInformation.Attribute.smoothing > 0;

            if (!context.typeCodeGenCache.TryGetValue(m_Template.TemplatePath + m_Template.TemplateOverridePath,
                                                      out var generator))
            {
                generator = new GhostCodeGen(m_Template.TemplatePath);

                if (!string.IsNullOrEmpty(m_Template.TemplateOverridePath))
                {
                    generator.AddTemplateOverrides(m_Template.TemplateOverridePath);
                }

                context.typeCodeGenCache.Add(m_Template.TemplatePath + m_Template.TemplateOverridePath, generator);
            }

            generator = generator.Clone();

            // Prefix and Variable Replacements
            var reference = string.IsNullOrEmpty(parent)
                ? m_TypeInformation.FieldName : $"{parent}.{m_TypeInformation.FieldName}";
            var name = reference.Replace('.', '_');

            generator.Replacements.Add("GHOST_FIELD_NAME", $"{name}");
            generator.Replacements.Add("GHOST_FIELD_REFERENCE", $"{reference}");
            generator.Replacements.Add("GHOST_FIELD_TYPE_NAME", m_TypeInformation.Type.GetFieldTypeName());

            if (quantization > 0)
            {
                generator.Replacements.Add("GHOST_QUANTIZE_SCALE", quantization.ToString());
                generator.Replacements.Add("GHOST_DEQUANTIZE_SCALE",
                                           $"{(1.0f / quantization).ToString(CultureInfo.InvariantCulture)}f");
            }
            float maxSmoothingDistSq  = m_TypeInformation.Attribute.maxSmoothingDist * m_TypeInformation.Attribute.maxSmoothingDist;
            bool  enableExtrapolation = m_TypeInformation.Attribute.smoothing == (uint)TypeAttribute.AttributeFlags.InterpolatedAndExtrapolated;

            generator.Replacements.Add("GHOST_MAX_INTERPOLATION_DISTSQ", maxSmoothingDistSq.ToString(CultureInfo.InvariantCulture));

            // Skip fragments which have been overridden already
            for (int i = 0; i < k_OverridableFragments.GetLength(0); i++)
            {
                if (overrides == null || !overrides.ContainsKey(k_OverridableFragments[i, 0]))
                {
                    var fragment       = k_OverridableFragments[i, 1];
                    var targetFragment = k_OverridableFragments[i, 0];
                    if (targetFragment == "GHOST_COPY_FROM_SNAPSHOT")
                    {
                        if (interpolate)
                        {
                            m_TargetGenerator.GenerateFragment(enableExtrapolation ? "GHOST_COPY_FROM_SNAPSHOT_ENABLE_EXTRAPOLATION" : "GHOST_COPY_FROM_SNAPSHOT_DISABLE_EXTRAPOLATION",
                                                               generator.Replacements, m_TargetGenerator, "GHOST_COPY_FROM_SNAPSHOT");
                            // The setup section is optional, so do not generate error if it is not present
                            generator.GenerateFragment("GHOST_COPY_FROM_SNAPSHOT_INTERPOLATE_SETUP", generator.Replacements, m_TargetGenerator,
                                                       "GHOST_COPY_FROM_SNAPSHOT", null, true);
                            // only generate max distance checks if clamp is enabled
                            if (maxSmoothingDistSq > 0)
                            {
                                generator.GenerateFragment("GHOST_COPY_FROM_SNAPSHOT_INTERPOLATE_DISTSQ", generator.Replacements, m_TargetGenerator,
                                                           "GHOST_COPY_FROM_SNAPSHOT");
                                m_TargetGenerator.GenerateFragment("GHOST_COPY_FROM_SNAPSHOT_INTERPOLATE_CLAMP_MAX", generator.Replacements, m_TargetGenerator,
                                                                   "GHOST_COPY_FROM_SNAPSHOT");
                            }
                        }
                        else
                        {
                            fragment = "GHOST_COPY_FROM_SNAPSHOT";
                        }
                    }
                    generator.GenerateFragment(fragment, generator.Replacements, m_TargetGenerator,
                                               targetFragment);
                }
            }

            // Imports
            var imports = generator.GetFragmentTemplate("GHOST_IMPORTS");

            if (!string.IsNullOrEmpty(imports))
            {
                foreach (var import in imports.Split('\n'))
                {
                    if (string.IsNullOrEmpty(import))
                    {
                        continue;
                    }
                    var matches = m_usingRegex.Matches(import);
                    if (matches.Count == 1)
                    {
                        context.imports.Add(matches[0].Value);
                    }
                }
            }

            ulong fieldHash = 0;

            fieldHash = Entities.TypeHash.CombineFNV1A64(fieldHash, Entities.TypeHash.FNV1A64(m_TypeInformation.Attribute.composite?1:0));
            fieldHash = Entities.TypeHash.CombineFNV1A64(fieldHash, Entities.TypeHash.FNV1A64(m_TypeInformation.Attribute.smoothing > 0 ? 1 : 0));
            fieldHash = Entities.TypeHash.CombineFNV1A64(fieldHash, (ulong)m_TypeInformation.Attribute.subtype);
            fieldHash = Entities.TypeHash.CombineFNV1A64(fieldHash, (ulong)m_TypeInformation.Attribute.quantization);
            context.FieldState.ghostfieldHash = Entities.TypeHash.CombineFNV1A64(context.FieldState.ghostfieldHash, fieldHash);

            if (m_TypeInformation.Type.Scope != null)
            {
                context.collectionAssemblies.Add(m_TypeInformation.Type.Scope.Name);
            }

            m_ActiveGenerator = generator;
        }
コード例 #16
0
        public void GenerateFields(CodeGenerator.Context context, string parent = null, Dictionary <string, GhostCodeGen.FragmentData> overrides = null)
        {
            if (m_Template == null)
            {
                return;
            }

            var quantization = m_TypeInformation.Attribute.quantization;
            var interpolate  = m_TypeInformation.Attribute.interpolate;

            if (!context.typeCodeGenCache.TryGetValue(m_Template.TemplatePath + m_Template.TemplateOverridePath,
                                                      out var generator))
            {
                generator = new GhostCodeGen(m_Template.TemplatePath);

                if (!string.IsNullOrEmpty(m_Template.TemplateOverridePath))
                {
                    generator.AddTemplateOverrides(m_Template.TemplateOverridePath);
                }

                context.typeCodeGenCache.Add(m_Template.TemplatePath + m_Template.TemplateOverridePath, generator);
            }

            generator = generator.Clone();

            // Prefix and Variable Replacements
            var reference = string.IsNullOrEmpty(parent)
                ? m_TypeInformation.FieldInfo.Name
                : $"{parent}.{m_TypeInformation.FieldInfo.Name}";
            var name = reference.Replace('.', '_');

            generator.Replacements.Add("GHOST_FIELD_NAME", $"{name}");
            generator.Replacements.Add("GHOST_FIELD_REFERENCE", $"{reference}");
            generator.Replacements.Add("GHOST_FIELD_TYPE_NAME", m_TypeInformation.Type.GetFieldTypeName());

            if (quantization > 0)
            {
                generator.Replacements.Add("GHOST_QUANTIZE_SCALE", quantization.ToString());
                generator.Replacements.Add("GHOST_DEQUANTIZE_SCALE",
                                           $"{(1.0f / quantization).ToString(CultureInfo.InvariantCulture)}f");
            }

            // Skip fragments which have been overridden already
            for (int i = 0; i < k_OverridableFragments.GetLength(0); i++)
            {
                if (overrides == null || !overrides.ContainsKey(k_OverridableFragments[i, 0]))
                {
                    var fragment       = k_OverridableFragments[i, 1];
                    var targetFragment = k_OverridableFragments[i, 0];
                    if (targetFragment == "GHOST_COPY_FROM_SNAPSHOT" && !interpolate)
                    {
                        fragment = "GHOST_COPY_FROM_SNAPSHOT";
                    }
                    generator.GenerateFragment(fragment, generator.Replacements, m_TargetGenerator,
                                               targetFragment);
                }
            }

            // Imports
            var imports = generator.GetFragmentTemplate("GHOST_IMPORTS");

            if (!string.IsNullOrEmpty(imports))
            {
                foreach (var import in imports.Split('\n'))
                {
                    if (string.IsNullOrEmpty(import))
                    {
                        continue;
                    }
                    var matches = m_usingRegex.Matches(import);
                    if (matches.Count == 1)
                    {
                        context.imports.Add(matches[0].Value);
                    }
                }
            }

            ulong fieldHash = 0;

            fieldHash = Entities.TypeHash.CombineFNV1A64(fieldHash, Entities.TypeHash.FNV1A64(m_TypeInformation.Attribute.composite?1:0));
            fieldHash = Entities.TypeHash.CombineFNV1A64(fieldHash, Entities.TypeHash.FNV1A64(m_TypeInformation.Attribute.interpolate?1:0));
            fieldHash = Entities.TypeHash.CombineFNV1A64(fieldHash, (ulong)m_TypeInformation.Attribute.subtype);
            fieldHash = Entities.TypeHash.CombineFNV1A64(fieldHash, (ulong)m_TypeInformation.Attribute.quantization);
            context.FieldState.ghostfieldHash = Entities.TypeHash.CombineFNV1A64(context.FieldState.ghostfieldHash, fieldHash);

            if (m_TypeInformation.Type.Scope != null)
            {
                context.collectionAssemblies.Add(m_TypeInformation.Type.Scope.Name);
            }

            m_ActiveGenerator = generator;
        }
コード例 #17
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);
        }
コード例 #18
0
        public Dictionary <string, GhostCodeGen.FragmentData> GenerateCompositeOverrides(CodeGenerator.Context context, string parent = null)
        {
            var fragments = new Dictionary <string, GhostCodeGen.FragmentData>();

            if (m_Template == null || string.IsNullOrEmpty(m_Template.TemplateOverridePath))
            {
                return(null);
            }

            var quantization = m_TypeInformation.Attribute.quantization;
            var interpolate  = m_TypeInformation.Attribute.interpolate;

            if (!context.typeCodeGenCache.TryGetValue(m_Template.TemplateOverridePath,
                                                      out var generator))
            {
                generator = new GhostCodeGen(m_Template.TemplateOverridePath);
                context.typeCodeGenCache.Add(m_Template.TemplateOverridePath, generator);
            }

            generator = generator.Clone();

            // Prefix and Variable Replacements
            var reference = string.IsNullOrEmpty(parent)
                ? m_TypeInformation.FieldInfo.Name
                : $"{parent}.{m_TypeInformation.FieldInfo.Name}";
            var name = reference.Replace('.', '_');

            generator.Replacements.Add("GHOST_FIELD_NAME", $"{name}");
            generator.Replacements.Add("GHOST_FIELD_REFERENCE", $"{reference}");
            generator.Replacements.Add("GHOST_FIELD_TYPE_NAME", m_TypeInformation.Type.GetFieldTypeName());

            if (quantization > 0)
            {
                generator.Replacements.Add("GHOST_QUANTIZE_SCALE", quantization.ToString());
                generator.Replacements.Add("GHOST_DEQUANTIZE_SCALE",
                                           $"{(1.0f / quantization).ToString(CultureInfo.InvariantCulture)}f");
            }

            // Type Info
            if (generator.GenerateFragment("GHOST_FIELD", generator.Replacements, m_TargetGenerator, null, null, true))
            {
                fragments.Add("GHOST_FIELD", m_TargetGenerator.Fragments["__GHOST_FIELD__"]);
            }
            // CopyToSnapshot
            if (generator.GenerateFragment("GHOST_COPY_TO_SNAPSHOT", generator.Replacements, m_TargetGenerator, null, null, true))
            {
                fragments.Add("GHOST_COPY_TO_SNAPSHOT", m_TargetGenerator.Fragments["__GHOST_COPY_TO_SNAPSHOT__"]);
            }
            // CopyFromSnapshot
            if (generator.GenerateFragment(
                    interpolate ? "GHOST_COPY_FROM_SNAPSHOT_INTERPOLATE" : "GHOST_COPY_FROM_SNAPSHOT",
                    generator.Replacements, m_TargetGenerator, "GHOST_COPY_FROM_SNAPSHOT", null, true))
            {
                fragments.Add("GHOST_COPY_FROM_SNAPSHOT", generator.Fragments["__GHOST_COPY_FROM_SNAPSHOT__"]);
                fragments.Add("GHOST_COPY_FROM_SNAPSHOT_INTERPOLATE", generator.Fragments["__GHOST_COPY_FROM_SNAPSHOT_INTERPOLATE__"]);
            }
            // RestoreFromBackup
            if (generator.GenerateFragment("GHOST_RESTORE_FROM_BACKUP", generator.Replacements, m_TargetGenerator, null, null, true))
            {
                fragments.Add("GHOST_RESTORE_FROM_BACKUP", m_TargetGenerator.Fragments["__GHOST_RESTORE_FROM_BACKUP__"]);
            }
            // PredictDelta
            if (generator.GenerateFragment("GHOST_PREDICT", generator.Replacements, m_TargetGenerator, null, null, true))
            {
                fragments.Add("GHOST_PREDICT", m_TargetGenerator.Fragments["__GHOST_PREDICT__"]);
            }

            // ReportPredictionError
            if (generator.GenerateFragment("GHOST_REPORT_PREDICTION_ERROR", generator.Replacements, m_TargetGenerator, null, null, true))
            {
                fragments.Add("GHOST_REPORT_PREDICTION_ERROR", m_TargetGenerator.Fragments["__GHOST_REPORT_PREDICTION_ERROR__"]);
            }
            // GetPredictionErrorName
            if (generator.GenerateFragment("GHOST_GET_PREDICTION_ERROR_NAME", generator.Replacements, m_TargetGenerator, null, null, true))
            {
                fragments.Add("GHOST_GET_PREDICTION_ERROR_NAME", m_TargetGenerator.Fragments["__GHOST_GET_PREDICTION_ERROR_NAME__"]);
            }

            ValidateOverridableFragments(generator.Fragments);

            m_ActiveGenerator = generator;
            return(fragments);
        }