|
| 1 | +using Improbable.Gdk.CodeGeneration.CodeWriter; |
| 2 | +using Improbable.Gdk.CodeGeneration.Model.Details; |
| 3 | +using NLog; |
| 4 | + |
| 5 | +namespace Improbable.Gdk.CodeGenerator |
| 6 | +{ |
| 7 | + public static class UnityComponentReplicationSystemGenerator |
| 8 | + { |
| 9 | + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); |
| 10 | + |
| 11 | + public static CodeWriter Generate(UnityComponentDetails componentDetails) |
| 12 | + { |
| 13 | + var componentNamespace = $"global::{componentDetails.Namespace}.{componentDetails.Name}"; |
| 14 | + |
| 15 | + Logger.Trace($"Generating {componentDetails.Namespace}.{componentDetails.Name}.ReplicationSystem internal class."); |
| 16 | + |
| 17 | + return CodeWriter.Populate(cgw => |
| 18 | + { |
| 19 | + cgw.UsingDirectives( |
| 20 | + "Improbable.Gdk.Core", |
| 21 | + "Improbable.Worker.CInterop", |
| 22 | + "Unity.Collections", |
| 23 | + "Unity.Entities", |
| 24 | + "Unity.Profiling" |
| 25 | + ); |
| 26 | + |
| 27 | + cgw.Namespace(componentDetails.Namespace, ns => |
| 28 | + { |
| 29 | + ns.Type($"public partial class {componentDetails.Name}", partial => |
| 30 | + { |
| 31 | + partial.Annotate("DisableAutoCreation, UpdateInGroup(typeof(SpatialOSSendGroup)), UpdateBefore(typeof(SpatialOSSendGroup.InternalSpatialOSSendGroup))") |
| 32 | + .Type("internal class ReplicationSystem : SystemBase", system => |
| 33 | + { |
| 34 | + system.Line($@" |
| 35 | +private NativeQueue<SerializedMessagesToSend.UpdateToSend> dirtyComponents; |
| 36 | +private SpatialOSSendSystem spatialOsSendSystem; |
| 37 | +
|
| 38 | +private ProfilerMarker foreachMarker = new ProfilerMarker(""{componentDetails.Name}SerializationJob""); |
| 39 | +
|
| 40 | +protected override void OnCreate() |
| 41 | +{{ |
| 42 | + spatialOsSendSystem = World.GetExistingSystem<SpatialOSSendSystem>(); |
| 43 | +}} |
| 44 | +"); |
| 45 | + system.Method("protected override void OnUpdate()", m => |
| 46 | + { |
| 47 | + m.Line(new[] |
| 48 | + { |
| 49 | + "dirtyComponents = new NativeQueue<SerializedMessagesToSend.UpdateToSend>(Allocator.TempJob);", |
| 50 | + "var dirtyComponentsWriter = dirtyComponents.AsParallelWriter();", |
| 51 | + "var marker = foreachMarker;", |
| 52 | + }); |
| 53 | + |
| 54 | + m.Line($@" |
| 55 | +Dependency = Entities.WithName(""{componentDetails.Name}Replication"")"); |
| 56 | + if (!componentDetails.IsBlittable) |
| 57 | + { |
| 58 | + m.Line(@" |
| 59 | + .WithoutBurst()"); |
| 60 | + } |
| 61 | + |
| 62 | + m.Line(@" |
| 63 | + .WithAll<HasAuthority>() |
| 64 | + .WithChangeFilter<Component>() |
| 65 | + .ForEach((ref Component component, in SpatialEntityId entity) => |
| 66 | + { |
| 67 | + marker.Begin(); |
| 68 | + if (!component.IsDataDirty()) |
| 69 | + { |
| 70 | + marker.End(); |
| 71 | + return; |
| 72 | + } |
| 73 | +
|
| 74 | + // Serialize component |
| 75 | + var schemaUpdate = SchemaComponentUpdate.Create(); |
| 76 | + Serialization.SerializeUpdate(component, schemaUpdate); |
| 77 | +
|
| 78 | + component.MarkDataClean(); |
| 79 | +
|
| 80 | + // Schedule update |
| 81 | + var componentUpdate = new ComponentUpdate(ComponentId, schemaUpdate); |
| 82 | + var update = new SerializedMessagesToSend.UpdateToSend(componentUpdate, entity.EntityId.Id); |
| 83 | + dirtyComponentsWriter.Enqueue(update); |
| 84 | + marker.End(); |
| 85 | + }) |
| 86 | + .ScheduleParallel(Dependency); |
| 87 | +
|
| 88 | +spatialOsSendSystem.AddReplicationJobProducer(Dependency, dirtyComponents); |
| 89 | +dirtyComponents = default; |
| 90 | +"); |
| 91 | + }); |
| 92 | + }); |
| 93 | + }); |
| 94 | + }); |
| 95 | + }); |
| 96 | + } |
| 97 | + } |
| 98 | +} |
0 commit comments