Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
EntityCloner.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System.Collections.Generic;
4 using System.IO;
5 using System.Linq;
6 using SiliconStudio.Core;
7 using SiliconStudio.Core.Serialization;
8 using SiliconStudio.Core.Serialization.Serializers;
9 using SiliconStudio.Paradox.DataModel;
10 using SiliconStudio.Paradox.Effects;
11 using SiliconStudio.Paradox.Engine;
12 using SiliconStudio.Paradox.Graphics;
13 
14 namespace SiliconStudio.Paradox.EntityModel
15 {
16  /// <summary>
17  /// Provides method for deep cloning of en <see cref="Entity"/>.
18  /// </summary>
19  [DataSerializerGlobal(typeof(CloneSerializer<Effect>), Profile = "Clone")]
20  [DataSerializerGlobal(typeof(CloneSerializer<SpriteGroup>), Profile = "Clone")]
21  [DataSerializerGlobal(typeof(CloneSerializer<BlendState>), Profile = "Clone")]
22  [DataSerializerGlobal(typeof(CloneSerializer<RasterizerState>), Profile = "Clone")]
23  [DataSerializerGlobal(typeof(CloneSerializer<SamplerState>), Profile = "Clone")]
24  [DataSerializerGlobal(typeof(CloneSerializer<DepthStencilState>), Profile = "Clone")]
25  [DataSerializerGlobal(typeof(CloneSerializer<Texture1D>), Profile = "Clone")]
26  [DataSerializerGlobal(typeof(CloneSerializer<Texture2D>), Profile = "Clone")]
27  [DataSerializerGlobal(typeof(CloneSerializer<Texture3D>), Profile = "Clone")]
28  [DataSerializerGlobal(typeof(CloneSerializer<TextureCube>), Profile = "Clone")]
29  [DataSerializerGlobal(typeof(ContentReferenceCloneDataSerializer<>), typeof(ContentReference<>), DataSerializerGenericMode.GenericArguments, Profile = "Clone")]
31  {
32  private static CloneContext cloneContext = new CloneContext();
33  private static SerializerSelector cloneSerializerSelector = null;
34  internal static PropertyKey<CloneContext> CloneContextProperty = new PropertyKey<CloneContext>("CloneContext", typeof(EntityCloner));
35 
36  /// <summary>
37  /// Clones the specified entity.
38  /// <see cref="Entity"/>, children <see cref="Entity"/> and their <see cref="EntityComponent"/> will be cloned.
39  /// Other assets will be shared.
40  /// </summary>
41  /// <param name="entity">The entity.</param>
42  /// <returns></returns>
43  public static Entity Clone(Entity entity)
44  {
45  var clonedObjects = new HashSet<object>();
46 
47  // Registers objects that should be cloned (Entity and their EntityComponent)
48  foreach (var currentEntity in ParameterContainerExtensions.CollectEntityTree(entity))
49  {
50  clonedObjects.Add(currentEntity);
51  foreach (var component in currentEntity.Tags.Where(x => x.Value is EntityComponent))
52  {
53  clonedObjects.Add(component.Value);
54  }
55  }
56 
57  return Clone(clonedObjects, null, entity);
58  }
59 
60  /// <summary>
61  /// Clones the specified object, taking special care of <see cref="Entity"/>, <see cref="EntityComponent"/> and external assets.
62  /// User can optionally provides list of cloned objects (list of data reference objects that should be cloned)
63  /// and mapped objects (list of data reference objects that should be ducplicated using the given instance).
64  /// </summary>
65  /// <typeparam name="T"></typeparam>
66  /// <param name="clonedObjects">The cloned objects.</param>
67  /// <param name="mappedObjects">The mapped objects.</param>
68  /// <param name="entity">The entity.</param>
69  /// <returns></returns>
70  private static T Clone<T>(HashSet<object> clonedObjects, TryGetValueFunction<object, object> mappedObjects, T entity) where T : class
71  {
72  if (cloneSerializerSelector == null)
73  {
74  cloneSerializerSelector = new SerializerSelector();
75  cloneSerializerSelector.ReuseReferences = true;
76 
77  cloneSerializerSelector
78  .RegisterProfile("Default")
79  .RegisterProfile("Clone")
80  .RegisterSerializer(new EntitySerializer())
81  .RegisterSerializer(new CloneSerializer<string>())
82  .RegisterSerializer(new CloneSerializer<Effect>())
83  .RegisterSerializer(new CloneSerializer<Mesh>())
84  .RegisterSerializer(new CloneSerializer<Model>())
85  .RegisterSerializer(new CloneSerializer<AnimationClip>());
86  }
87 
88  // Initialize CloneContext
89  lock (cloneContext)
90  {
91  try
92  {
93  cloneContext.EntitySerializerSelector = cloneSerializerSelector;
94 
95  cloneContext.ClonedObjects = clonedObjects;
96  cloneContext.MappedObjects = mappedObjects;
97 
98  // Serialize
99  var memoryStream = cloneContext.MemoryStream;
100  var writer = new BinarySerializationWriter(memoryStream);
101  writer.Context.SerializerSelector = cloneSerializerSelector;
102  writer.Context.Set(CloneContextProperty, cloneContext);
103  writer.SerializeExtended(entity, ArchiveMode.Serialize, null);
104 
105  // Deserialization reuses this list and expect it to be empty at the beginning.
106  cloneContext.SerializedObjects.Clear();
107 
108  // Deserialize
109  T result = null;
110  memoryStream.Seek(0, SeekOrigin.Begin);
111  var reader = new BinarySerializationReader(memoryStream);
112  reader.Context.SerializerSelector = cloneSerializerSelector;
113  reader.Context.Set(CloneContextProperty, cloneContext);
114  reader.SerializeExtended(ref result, ArchiveMode.Deserialize, null);
115 
116  return result;
117  }
118  finally
119  {
120  cloneContext.Cleanup();
121  }
122  }
123  }
124 
125  public delegate bool TryGetValueFunction<in TKey, TResult>(TKey key, out TResult result);
126 
127  /// <summary>
128  /// Helper class for cloning <see cref="Entity"/>.
129  /// </summary>
130  internal class CloneContext
131  {
132  public void Cleanup()
133  {
134  MemoryStream.SetLength(0);
135  MappedObjects = null;
136  SerializedObjects.Clear();
137  ContentReferences.Clear();
138  ClonedObjects = null;
139  SharedObjects.Clear();
140  EntitySerializerSelector = null;
141  }
142 
143  public MemoryStream MemoryStream = new MemoryStream(4096);
144 
145  public TryGetValueFunction<object, object> MappedObjects;
146 
147  public readonly HashSet<object> SerializedObjects = new HashSet<object>();
148 
149  public readonly List<ContentReference> ContentReferences = new List<ContentReference>();
150 
151  /// <summary>
152  /// Lists objects that should be cloned.
153  /// </summary>
154  public HashSet<object> ClonedObjects;
155 
156  /// <summary>
157  /// Stores objects that should be reused in the new cloned instance.
158  /// </summary>
159  public readonly List<object> SharedObjects = new List<object>();
160 
161  /// <summary>
162  /// Special serializer that goes through <see cref="EntitySerializerSelector"/> and <see cref="EntityComponentSerializer{T}"/>.
163  /// </summary>
164  public SerializerSelector EntitySerializerSelector;
165  }
166 
167  }
168 }
Game entity. It usually aggregates multiple EntityComponent
Definition: Entity.cs:28
DataSerializerGenericMode
Defines what generic parameters to pass to the serializer.
static Entity Clone(Entity entity)
Clones the specified entity. Entity, children Entity and their EntityComponent will be cloned...
Definition: EntityCloner.cs:43
Implements SerializationStream as a binary writer.
Implements SerializationStream as a binary reader.
Serializer context. It holds DataSerializer{T} objects and their factories.
A class that represents a tag propety.
Definition: PropertyKey.cs:17
Provides method for deep cloning of en Entity.
Definition: EntityCloner.cs:30