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); }
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(); }
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); }
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; } }
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; } } ; }
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); } }
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; }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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; }
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; }
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); }
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); }