/// <summary> /// Handler for if a child string changes /// </summary> /// <param name="elementID">Element Id</param> /// <param name="newValue">New Value</param> protected virtual void OnStringElementChanged(long elementID, XString newValue) { if (primitiveMap.ContainsKey(elementID)) { SyncPrimitive primitive = primitiveMap[elementID]; primitive.UpdateFromRemote(newValue); NotifyPrimitiveChanged(primitive); } else { LogUnknownElement(elementID.ToString(), newValue.GetString(), typeof(string)); } }
/// <summary> /// Handler for if a child double changes /// </summary> /// <param name="elementID">Element Id</param> /// <param name="newValue">New Value</param> protected virtual void OnDoubleElementChanged(long elementID, double newValue) { if (primitiveMap.ContainsKey(elementID)) { SyncPrimitive primitive = primitiveMap[elementID]; primitive.UpdateFromRemote(newValue); NotifyPrimitiveChanged(primitive); } else { LogUnknownElement(elementID.ToString(), newValue.ToString(CultureInfo.InvariantCulture), typeof(double)); } }
/// <summary> /// Register a new data model primitive as part of this object. Can be called multiple times on the same child. /// </summary> /// <param name="data">Sync Primitive Data</param> protected void AddChild(SyncPrimitive data) { if (data.HasNetworkElement) { long guid = data.Guid; Assert.AreNotEqual(SharingClient.kInvalidXGuid, guid, "A primitive GUID should never be invalid if it is networked."); primitiveMap.Add(guid, data); } if (!primitives.Contains(data)) { primitives.Add(data); } }
/// <summary> /// Remove a child primitive that belongs to this object. /// </summary> /// <param name="data">Sync Primitive Data</param> protected void RemoveChild(SyncPrimitive data) { // Manually remove from maps if (primitives.Remove(data) && data.HasNetworkElement) { primitiveMap.Remove(data.NetworkElement.GetGUID()); // Object has been removed internally, notify network ObjectElement parentElement = ObjectElement.Cast(data.NetworkElement.GetParent()); if (parentElement != null) { parentElement.RemoveElement(data.NetworkElement); } } }
/// <summary> /// Initializes this object for local use. Doesn't wait for network initialization. /// </summary> /// <param name="parentElement">Parent element of this SyncObject.</param> public override void InitializeLocal(ObjectElement parentElement) { // Auto create element if needed if (Element == null) { Element = parentElement.CreateObjectElement(XStringFieldName, GetType().FullName, Owner); NetworkElement = Element; } // Initialize all primitives for (int i = 0; i < primitives.Count; i++) { SyncPrimitive data = primitives[i]; data.InitializeLocal(Element); primitiveMap[data.Guid] = data; } // Complete the initialization if (InitializationComplete != null) { InitializationComplete(this); } }
protected virtual void NotifyPrimitiveChanged(SyncPrimitive primitive) { ObjectChanged.RaiseEvent(this); }
private void InitializePrimitives() { primitiveMap = new Dictionary <long, SyncPrimitive>(); primitives = new List <SyncPrimitive>(); // Scan the type of object this is a look for the SyncDataAttribute Type baseType = GetType(); #if WINDOWS_UWP var typeFields = baseType.GetRuntimeFields(); #else var typeFields = baseType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); #endif foreach (FieldInfo typeField in typeFields) { SyncDataAttribute attribute = null; #if WINDOWS_UWP attribute = typeField.GetCustomAttribute <SyncDataAttribute>(true); #else object[] customAttributes = typeField.GetCustomAttributes(typeof(SyncDataAttribute), true); if (customAttributes.Length > 0) { attribute = customAttributes[0] as SyncDataAttribute; } #endif if (attribute != null) { Type fieldType = typeField.FieldType; string memberName = typeField.Name; // Override the member name if provided if (!string.IsNullOrEmpty(attribute.CustomFieldName)) { memberName = attribute.CustomFieldName; } // Auto instantiate the primitive if it doesn't already exist SyncPrimitive dataPrimitive = typeField.GetValue(this) as SyncPrimitive; if (dataPrimitive == null) { try { // Constructors are not inherited, as per Section 1.6.7.1 of the C# Language Specification. // This means that if a class subclasses Object or Primitive, they must either declare a constructor // that takes the "memberName" property or use the default (parameter less constructor). // First check if there is a constructor that takes the member name and if so call it bool hasConstructor = fieldType.GetConstructor(new[] { typeof(string) }) != null; if (hasConstructor) { dataPrimitive = (SyncPrimitive)Activator.CreateInstance(fieldType, memberName); } else { // Fallback on using the default constructor and manually assign the member name dataPrimitive = (SyncPrimitive)Activator.CreateInstance(fieldType, null); dataPrimitive.FieldName = memberName; } typeField.SetValue(this, dataPrimitive); } catch (Exception ex) { Debug.LogWarningFormat("Unable to create SyncPrimitive of type {0}. Exception: {1}", memberName, ex); } } if (dataPrimitive != null) { // Register the child AddChild(dataPrimitive); } } } }