public void GenerateSerializer(CodeGenerator.Context context, Mono.Cecil.TypeDefinition type) { var replacements = new Dictionary <string, string>(); if (context.FieldState.curChangeMask > 0) { replacements.Add("GHOST_CHANGE_MASK_BITS", context.FieldState.curChangeMask.ToString()); m_TargetGenerator.GenerateFragment("GHOST_FLUSH_FINAL_COMPONENT_CHANGE_MASK", replacements); } if (type.Namespace != null && type.Namespace != "") { context.imports.Add(type.Namespace); } foreach (var ns in context.imports) { replacements["GHOST_USING"] = CodeGenNamespaceUtils.GetValidNamespaceForType(context.generatedNs, ns); m_TargetGenerator.GenerateFragment("GHOST_USING_STATEMENT", replacements); } context.collectionAssemblies.Add(type.Module.Assembly.Name.Name); replacements.Clear(); replacements.Add("GHOST_NAME", type.FullName.Replace(".", "").Replace("/", "_")); replacements.Add("GHOST_NAMESPACE", context.generatedNs); replacements.Add("GHOST_COMPONENT_TYPE", type.FullName.Replace("/", ".")); replacements.Add("GHOST_CHANGE_MASK_BITS", context.FieldState.numFields.ToString()); replacements.Add("GHOST_FIELD_HASH", context.FieldState.ghostfieldHash.ToString()); replacements.Add("GHOST_COMPONENT_EXCLUDE_FROM_COLLECTION_HASH", context.IsRuntimeAssembly ? "0" : "1"); var ghostAttributes = CecilExtensions.GetGhostComponentAttribute(type); if (ghostAttributes != null && (ghostAttributes.OwnerPredictedSendType == GhostSendType.Interpolated || (ghostAttributes.PrefabType & GhostPrefabType.Client) == GhostPrefabType.InterpolatedClient)) { replacements.Add("GHOST_SEND_MASK", "GhostComponentSerializer.SendMask.Interpolated"); } else if (ghostAttributes != null && (ghostAttributes.OwnerPredictedSendType == GhostSendType.Predicted || (ghostAttributes.PrefabType & GhostPrefabType.Client) == GhostPrefabType.PredictedClient)) { replacements.Add("GHOST_SEND_MASK", "GhostComponentSerializer.SendMask.Predicted"); } else { replacements.Add("GHOST_SEND_MASK", "GhostComponentSerializer.SendMask.Interpolated | GhostComponentSerializer.SendMask.Predicted"); } replacements.Add("GHOST_SEND_CHILD_ENTITY", (ghostAttributes != null && !ghostAttributes.SendDataForChildEntity)?"0":"1"); if (m_TargetGenerator.Fragments["__GHOST_REPORT_PREDICTION_ERROR__"].Content.Length > 0) { m_TargetGenerator.GenerateFragment("GHOST_PREDICTION_ERROR_HEADER", replacements, m_TargetGenerator); } var serializerName = type.FullName.Replace("/", "+") + "Serializer.cs"; m_TargetGenerator.GenerateFile("", context.outputFolder, serializerName, replacements, context.batch); context.generatedTypes.Add(replacements["GHOST_NAME"]); }
public void GenerateSerializer(CodeGenerator.Context context, Mono.Cecil.TypeDefinition typeDefinition) { var replacements = new Dictionary <string, string>(); replacements.Add("COMMAND_NAME", typeDefinition.FullName.Replace(".", "").Replace("/", "_")); replacements.Add("COMMAND_NAMESPACE", context.generatedNs); replacements.Add("COMMAND_COMPONENT_TYPE", typeDefinition.FullName.Replace("/", ".")); context.collectionAssemblies.Add(typeDefinition.Module.Assembly.Name.Name); if (typeDefinition.Namespace != null && typeDefinition.Namespace != "") { context.imports.Add(typeDefinition.Namespace); } foreach (var ns in context.imports) { replacements["COMMAND_USING"] = CodeGenNamespaceUtils.GetValidNamespaceForType(context.generatedNs, ns); m_CommandGenerator.GenerateFragment("COMMAND_USING_STATEMENT", replacements); } var serializerName = typeDefinition.FullName.Replace("/", "+") + "CommandSerializer.cs"; m_CommandGenerator.GenerateFile("", context.outputFolder, serializerName, replacements, context.batch); }
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); }
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); }
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); }
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 void GenerateSerializer(CodeGenerator.Context context, Mono.Cecil.TypeDefinition generatorType, Mono.Cecil.TypeDefinition componentType, GhostComponentAttribute ghostAttributes) { var replacements = new Dictionary <string, string>(); if (context.FieldState.curChangeMask > 0) { replacements.Add("GHOST_CHANGE_MASK_BITS", context.FieldState.curChangeMask.ToString()); m_TargetGenerator.GenerateFragment("GHOST_FLUSH_FINAL_COMPONENT_CHANGE_MASK", replacements); } if (componentType.Namespace != null && componentType.Namespace != "") { context.imports.Add(componentType.Namespace); } foreach (var ns in context.imports) { replacements["GHOST_USING"] = CodeGenNamespaceUtils.GetValidNamespaceForType(context.generatedNs, ns); m_TargetGenerator.GenerateFragment("GHOST_USING_STATEMENT", replacements); } context.collectionAssemblies.Add(componentType.Module.Assembly.Name.Name); if (generatorType != componentType) { context.collectionAssemblies.Add(generatorType.Module.Assembly.Name.Name); } replacements.Clear(); replacements.Add("GHOST_NAME", generatorType.FullName.Replace(".", "").Replace("/", "_")); replacements.Add("GHOST_NAMESPACE", context.generatedNs); replacements.Add("GHOST_COMPONENT_TYPE", componentType.FullName.Replace("/", ".")); replacements.Add("GHOST_CHANGE_MASK_BITS", context.FieldState.numFields.ToString()); replacements.Add("GHOST_FIELD_HASH", context.FieldState.ghostfieldHash.ToString()); replacements.Add("GHOST_COMPONENT_EXCLUDE_FROM_COLLECTION_HASH", context.IsRuntimeAssembly ? "0" : "1"); replacements.Add("GHOST_VARIANT_HASH", context.VariantHash.ToString()); if (ghostAttributes != null) { if (ghostAttributes.OwnerPredictedSendType == GhostSendType.Interpolated || (ghostAttributes.PrefabType & GhostPrefabType.Client) == GhostPrefabType.InterpolatedClient) { replacements.Add("GHOST_SEND_MASK", "GhostComponentSerializer.SendMask.Interpolated"); } else if (ghostAttributes.OwnerPredictedSendType == GhostSendType.Predicted || (ghostAttributes.PrefabType & GhostPrefabType.Client) == GhostPrefabType.PredictedClient) { replacements.Add("GHOST_SEND_MASK", "GhostComponentSerializer.SendMask.Predicted"); } else if (ghostAttributes.PrefabType == GhostPrefabType.Server) { replacements.Add("GHOST_SEND_MASK", "GhostComponentSerializer.SendMask.None"); } else { replacements.Add("GHOST_SEND_MASK", "GhostComponentSerializer.SendMask.Interpolated | GhostComponentSerializer.SendMask.Predicted"); } replacements.Add("GHOST_SEND_CHILD_ENTITY", ghostAttributes.SendDataForChildEntity?"1":"0"); var ownerType = ghostAttributes.OwnerSendType; if (componentType.IsICommandData() && (ghostAttributes.OwnerSendType & SendToOwnerType.SendToOwner) != 0) { UnityEngine.Debug.LogError($"ICommandData {componentType.FullName} is configured to be sent to ghost owner. It will be ignored"); ownerType &= ~SendToOwnerType.SendToOwner; } replacements.Add("GHOST_SEND_OWNER", "SendToOwnerType." + ownerType); } else if (!componentType.IsICommandData()) { replacements.Add("GHOST_SEND_MASK", "GhostComponentSerializer.SendMask.Interpolated | GhostComponentSerializer.SendMask.Predicted"); replacements.Add("GHOST_SEND_OWNER", "SendToOwnerType.All"); replacements.Add("GHOST_SEND_CHILD_ENTITY", "1"); } else { replacements.Add("GHOST_SEND_MASK", "GhostComponentSerializer.SendMask.Predicted"); replacements.Add("GHOST_SEND_OWNER", "SendToOwnerType.SendToNonOwner"); replacements.Add("GHOST_SEND_CHILD_ENTITY", "0"); } if (componentType.IsBufferElementData()) { m_TargetGenerator.GenerateFragment("GHOST_COPY_FROM_BUFFER", replacements, m_TargetGenerator, "COPY_FROM_SNAPSHOT_SETUP"); } else { m_TargetGenerator.GenerateFragment("GHOST_COPY_FROM_COMPONENT", replacements, m_TargetGenerator, "COPY_FROM_SNAPSHOT_SETUP"); } if (m_TargetGenerator.Fragments["__GHOST_REPORT_PREDICTION_ERROR__"].Content.Length > 0) { m_TargetGenerator.GenerateFragment("GHOST_PREDICTION_ERROR_HEADER", replacements, m_TargetGenerator); } var serializerName = generatorType.FullName.Replace("/", "+") + "Serializer.cs"; m_TargetGenerator.GenerateFile("", context.outputFolder, serializerName, replacements, context.batch); context.generatedTypes.Add(replacements["GHOST_NAME"]); }