private void DoCall(Node Target) { switch (Type) { case TypeOfCall.RPC: MethodInfo methodInfo = MDStatics.GetMethodInfo(Target, Convert.ToInt32(Name)); if (methodInfo == null) { MDLog.Fatal(LOG_CAT, $"Could not find method {Target.GetType().ToString()}#{Name}"); return; } object[] convertedParams = MDStatics.ConvertParametersBackToObject(methodInfo, Parameters); MDStatics.GetReplicator().RpcSenderId = SenderPeerId; methodInfo.Invoke(Target, convertedParams); MDStatics.GetReplicator().RpcSenderId = -1; break; case TypeOfCall.RSET: MemberInfo memberInfo = MDStatics.GetMemberInfo(Target, Name); IMDDataConverter Converter = MDStatics.GetConverterForType(memberInfo.GetUnderlyingType()); object value = Converter.ConvertBackToObject(memberInfo.GetValue(Target), Parameters); MDLog.Trace(LOG_CAT, $"Setting {Name} on {Target.Name} to value {value}"); memberInfo.SetValue(Target, value); break; } }
/// <summary> /// Converts a set of parameters that were sent back to an object /// </summary> /// <param name="MethodInfo">The method info to convert for</param> /// <param name="Parameters">The parameters</param> /// <returns></returns> public static object[] ConvertParametersBackToObject(MethodInfo MethodInfo, params object[] Parameters) { if (Parameters == null || Parameters.Length == 0) { return(Parameters); } ParameterInfo[] CandidateParams = MethodInfo.GetParameters(); List <object> ConvertedParams = new List <object>(); for (int i = 0; i < Parameters.Length; i++) { // key0 = index, key1 = length object[] keys = Parameters[i].ToString().Split(SEPARATOR); int index = Convert.ToInt32(keys[0].ToString()); int length = Convert.ToInt32(keys[1].ToString()); // Extract parameters and use data converter object[] converterParams = Parameters.SubArray(i + 1, i + length); IMDDataConverter Converter = GetConverterForType(CandidateParams[index].ParameterType); object convertedValue = Converter.ConvertBackToObject(null, converterParams); // Add the value to our list ConvertedParams.Add(convertedValue); i += length; } return(ConvertedParams.ToArray()); }
/// <summary> /// Parses the settings we know about /// </summary> /// <param name="SettingsValues">A setting array that has been run through MDReplicator.ParseParameters</param> protected void ParseSettings(MDReplicatedSetting[] SettingsValues) { foreach (MDReplicatedSetting setting in SettingsValues) { switch ((Settings)setting.Key) { case Settings.OnValueChangedEvent: Node Node = NodeRef.GetRef() as Node; OnValueChangedMethodCallback = Node.GetType().GetMethodRecursive(setting.Value.ToString()); if (OnValueChangedMethodCallback == null) { OnValueChangedEventCallback = Node.GetType().GetEvent(setting.Value.ToString()); } MDLog.CError(OnValueChangedMethodCallback == null && OnValueChangedEventCallback == null, LOG_CAT, $"Failed to find method or event with name {setting.Value.ToString()} on Node {Node.GetPath()}"); break; case Settings.Converter: Type DataConverterType = Type.GetType(setting.Value.ToString()); DataConverter = MDStatics.CreateConverterOfType(DataConverterType); break; case Settings.CallOnValueChangedEventLocally: ShouldCallOnValueChangedCallbackLocally = setting.Value as bool? ?? false; break; } } // We got no data converter, get default one if (DataConverter == null) { DataConverter = MDStatics.GetConverterForType(Member.GetUnderlyingType()); } }
/// <summary> /// Sends a clocked rset to another client /// </summary> /// <param name="PeerId">The peer to send to</param> /// <param name="Reliability">Reliability to send at</param> /// <param name="Target">The node that is the target of our rpc call</param> /// <param name="MemberName">The name of the member to set</param> /// <param name="Value">The value to set</param> public void SendClockedRset(int PeerId, MDReliability Reliability, Node Target, string MemberName, object Value) { if (PeerId == MDStatics.GetPeerId()) { // This is to ourselves so just set Target.SetMemberValue(MemberName, Value); return; } MDRemoteMode Mode = MDStatics.GetMemberRpcType(Target, MemberName); MemberInfo info = MDStatics.GetMemberInfo(Target, MemberName); IMDDataConverter Converter = MDStatics.GetConverterForType(info.GetUnderlyingType()); switch (Mode) { case MDRemoteMode.Master: if (!Target.IsNetworkMaster()) { // Remote invoke master only SendClockedCall(PeerId, ClockedRemoteCall.TypeOfCall.RSET, Reliability, Target.GetPath(), MemberName, Mode, Converter.ConvertForSending(Value, true)); } break; case MDRemoteMode.MasterSync: if (!Target.IsNetworkMaster()) { // Remote invoke master only SendClockedCall(PeerId, ClockedRemoteCall.TypeOfCall.RSET, Reliability, Target.GetPath(), MemberName, Mode, Converter.ConvertForSending(Value, true)); } Target.SetMemberValue(MemberName, Value); break; case MDRemoteMode.Puppet: case MDRemoteMode.Remote: // Remote invoke SendClockedCall(PeerId, ClockedRemoteCall.TypeOfCall.RSET, Reliability, Target.GetPath(), MemberName, Mode, Converter.ConvertForSending(Value, true)); break; case MDRemoteMode.PuppetSync: case MDRemoteMode.RemoteSync: // Remote invoke and local invoke SendClockedCall(PeerId, ClockedRemoteCall.TypeOfCall.RSET, Reliability, Target.GetPath(), MemberName, Mode, Converter.ConvertForSending(Value, true)); Target.SetMemberValue(MemberName, Value); break; } }
/// <summary> /// Adds a data converter to the cache for the given type. This converter will be returned when using /// MDstatics.GetConverterForType() once it is in the cache. /// </summary> /// <param name="Type">The type to add the converter for, include generic typing</param> /// <param name="DataConverter">The data converter</param> /// <returns>True if added, false if not</returns> public static bool AddDataConverterForTypeToCache(Type Type, IMDDataConverter DataConverter) { if (Type == null || DataConverter == null) { return(false); } if (!DataConverterCache.ContainsKey(Type)) { DataConverterCache.Add(Type, DataConverter); return(true); } return(false); }
/// <summary> /// Get the data converter for the given type /// </summary> /// <param name="Type">The type to get the data converter for</param> /// <returns>The default data converter for this type</returns> public static IMDDataConverter GetConverterForType(Type Type) { if (!DataConverterCache.ContainsKey(Type)) { IMDDataConverter converter = _InternalGetConverterForType(Type); if (converter.AllowCachingOfConverter()) { DataConverterCache.Add(Type, converter); } else { return(converter); } } return(DataConverterCache[Type]); }
/// <summary> /// Adds a data converter to the cache for the given type. This converter will be returned when using /// MDstatics.GetConverterForType() once it is in the cache. /// </summary> /// <param name="Type">The type to add the converter for, include generic typing</param> /// <param name="DataConverterType">The type of the data converter</param> /// <returns>True if added, false if not</returns> public static bool AddDataConverterForTypeToCache(Type Type, Type DataConverterType) { if (Type == null || DataConverterType == null) { return(false); } if (DataConverterType.IsAssignableFrom(typeof(IMDDataConverter)) && !DataConverterCache.ContainsKey(Type)) { IMDDataConverter converter = Activator.CreateInstance(DataConverterType) as IMDDataConverter; DataConverterCache.Add(Type, converter); return(true); } return(false); }
/// <summary> /// Create a data converter of the given type or get it from the buffer if it already exists /// </summary> /// <param name="ConverterType">The data converter type to create</param> /// <returns>The data convert for that type or null if it is not a valid data converter</returns> public static IMDDataConverter CreateConverterOfType(Type DataConverterType) { if (DataConverterType != null && DataConverterType.IsAssignableFrom(typeof(IMDDataConverter))) { if (!DataConverterTypeCache.ContainsKey(DataConverterType)) { IMDDataConverter converter = Activator.CreateInstance(DataConverterType) as IMDDataConverter; if (converter.AllowCachingOfConverter()) { DataConverterTypeCache.Add(DataConverterType, converter); } else { return(converter); } } return(DataConverterTypeCache[DataConverterType]); } return(null); }
public object[] ConvertForSending(object Item, bool Complete) { ExtractMembers(); if (Item == null) { return(new object[] { null }); } List <object> ObjectArray = new List <object>(); List <object> newLastValues = new List <object>(); for (int i = 0; i < Members.Count; i++) { object value = Members[i].GetValue(Item); IMDDataConverter Converter = DataConverters[i]; if (Complete || LastValues.Count == 0 || Converter.ShouldObjectBeReplicated(LastValues[i], value)) { object[] dataArray = Converter.ConvertForSending(value, Complete); if (dataArray != null) { ObjectArray.Add($"{i}{SEPARATOR}{dataArray.Length}"); ObjectArray.AddRange(dataArray); } else { ObjectArray.Add($"{i}{SEPARATOR}{1}"); ObjectArray.Add(null); } } newLastValues.Add(value); } MDLog.Trace(LOG_CAT, $"MDCustomClass converting for sending ({MDStatics.GetParametersAsString(ObjectArray.ToArray())})"); LastValues = newLastValues; return(ObjectArray.ToArray()); }
/// <summary> /// Parses the settings we know about /// </summary> /// <param name="SettingsValues">A setting array that has been run through MDReplicator.ParseParameters</param> protected void ParseSettings(MDReplicatedSetting[] SettingsValues) { foreach (MDReplicatedSetting setting in SettingsValues) { switch ((Settings)setting.Key) { case Settings.OnValueChangedEvent: Node Node = NodeRef.GetRef() as Node; OnValueChangedCallback = Node.GetType().GetMethodRecursive(setting.Value.ToString()); break; case Settings.Converter: Type DataConverterType = Type.GetType(setting.Value.ToString()); DataConverter = MDStatics.CreateConverterOfType(DataConverterType); break; } } // We got no data converter, get default one if (DataConverter == null) { DataConverter = MDStatics.GetConverterForType(Member.GetUnderlyingType()); } }
/// <summary> /// Converts the parameters for sending /// </summary> /// <param name="MethodInfo">The method the parameters are for</param> /// <param name="Parameters">The parameters</param> /// <returns>List of converted parameters</returns> public static object[] ConvertParametersForSending(MethodInfo MethodInfo, params object[] Parameters) { ParameterInfo[] CandidateParams = MethodInfo.GetParameters(); List <object> NewParams = new List <object>(); for (int i = 0; i < CandidateParams.Length; i++) { IMDDataConverter Converter = GetConverterForType(CandidateParams[i].ParameterType); object[] paramsForSending = new object[] { null }; if (Parameters != null && i < Parameters.Length) { paramsForSending = Converter.ConvertForSending(Parameters[i], true); NewParams.Add($"{i}{SEPARATOR}{paramsForSending.Length}"); } else { NewParams.Add($"{i}{SEPARATOR}{1}"); } NewParams.AddRange(paramsForSending); } return(NewParams.ToArray()); }