The new MDList feature brought with it the IMDDataConverter interface, this interface is used so that you can have a list of any type you want including custom classes as long as you provide a data converter. A default converter is provided that supports the basic godot types that do not require conversion.
In addition the MDReplicatedCommandReplicator also has support for OnValueChangedEvent which was introduced when the MDClockedReplicatedMember was introduced.
So right now the support for these features look like this:
MDReplicatedMember N/A
MDClockedReplicatedMember - OnValueChangedEvent
MDCRMInterpolatedVector2 - OnValueChangedEvent (Inherited from MDClockedReplicatedMember)
MDReplicatedCommandReplicator - OnValueChangedEvent (has it's own implementation)
MDList - This is not a replicated member but it has support for the IMDDataConvert. The setting for the convert is in MDReplicatedCommandReplicator
I think this is confusing and I think most of this functionality should be moved into the MDReplicatedMember if possible so all classes that inherit can support the same functionality.
However to do this we will need one big change, currently MDReplicatedMember does replication by calling Rset and RSetUnreliable directly on the node, all other replicators send their messages through the MDReplicator.
Code from MDReplicatedMember
///<summary>Replicate this value to all clients</summary>
protected virtual void ReplicateToAll(Node Node, object Value)
{
MDLog.Debug(LOG_CAT, $"Replicating {Member.Name} with value {Value} from {LastValue}");
if (IsReliable())
{
Node.Rset(Member.Name, Value);
}
else
{
Node.RsetUnreliable(Member.Name, Value);
}
LastValue = Value;
}
The MDClockedReplicatedMember on the other hand sends it through the replicator
///<summary>Replicate this value to all clients</summary>
protected override void ReplicateToAll(Node Node, object Value)
{
MDLog.Debug(LOG_CAT, $"Replicating {Member.Name} with value {Value} from {LastValue}");
if (IsReliable())
{
Replicator.Rpc(REPLICATE_METHOD_NAME, Replicator.GetReplicationIdForKey(GetUniqueKey()),
GameClock.GetTick(), Value);
}
else
{
Replicator.RpcUnreliable(REPLICATE_METHOD_NAME, Replicator.GetReplicationIdForKey(GetUniqueKey()),
GameClock.GetTick(), Value);
}
LastValue = Value;
}
The MDReplicatedCommandReplicator is slightly different
To allow support for data converters and for the value change event we would need to modify the MDReplicatedMember to send its messages through the replicator just like MDClockedReplicatedMember does. In addition it should be noted that the MDReplicatedCommandReplicator supports both GameClock and no-GameClock modes in the same class. This is would also be possible for MDReplicatedMember if we send the commands through the MDReplicator.
Suggested Solution
I propose that we redo the replicated members so we end up with the following end result
MDReplicatedMember
Combine the MDClockedReplicatedMember and the MDReplicatedMember into one
Values would always go through the MDReplicator, regardless of if GameClock is enabled
Support for IMDDataConverter and OnValueChangedEvent
If the IMDDataConverter setting is not specified we should check if the member we are replicating implements the interface. This would allow any class that implements the IMDDataConverter to be replicated without setting a setting for it. See example below.
MDRInterpolatedVector2
This is the renamed MDCRMInterpolatedVector2, would mostly stay the same except inherits from MDReplicatedMember
MDReplicatedCommandReplicator
Mostly stays the same except Converter and OnValueChangedEvent are supplied by MDReplicatedMember instead of it's own implementation.
MDList
Stays the same
Benefits of this change
All current and future replicated members would support OnValueChangedEvent.
All settings for replicated members will be combined into MDReplicatedMember.Settings
IMDDataConverter support will mean that you can replicate any class as long as you provide a data converter.
No more need to write your own MDReplicatedMember for custom classes, just implement the data converter interface.
No need to set the MDReplicatedSetting for data converter unless your data converter is separate from your custom class.
No outside difference between the clocked / not clocked replicated members, meaning less replicated members
No more duplicated code in all the different replicated members (eg. for OnValueChangedEvent)
Example of how a class could be it's own data converter and thus be replicated. You can note there is no need to set the data converter setting since the interface is implemented directly in the class. This change would need to be made for the MDList as well.
[MDReplicated]
protected MyObject CustomObject = new MyObject();
[MDReplicated]
protected MDList<MyObject> ObjectList;
public class MyObject : IMDDataConverter
{
public string Value1 { get; set; }
public int Value2 { get; set; }
public bool Value3 {get; set; }
public object[] ConvertToObjectArray(object item)
{
MyObject obj = item as MyObject;
return new object[] { obj.Value1, obj.Value2, obj.Value3 };
}
public object ConvertFromObjectArray(object[] Parameters)
{
MyObject obj = new MyObject();
obj.Value1 = Parameters[0] as String;
obj.Value2 = Convert.ToInt32(Parameters[1]);
obj.Value3 = Boolean.Parse(Parameters[2].ToString());
return obj;
}
public int GetParametersConsumedByLastConversion()
{
return 3;
}
}
The Problem
The new MDList feature brought with it the IMDDataConverter interface, this interface is used so that you can have a list of any type you want including custom classes as long as you provide a data converter. A default converter is provided that supports the basic godot types that do not require conversion.
In addition the MDReplicatedCommandReplicator also has support for OnValueChangedEvent which was introduced when the MDClockedReplicatedMember was introduced.
So right now the support for these features look like this:
I think this is confusing and I think most of this functionality should be moved into the MDReplicatedMember if possible so all classes that inherit can support the same functionality.
However to do this we will need one big change, currently MDReplicatedMember does replication by calling Rset and RSetUnreliable directly on the node, all other replicators send their messages through the MDReplicator.
Code from MDReplicatedMember
The MDClockedReplicatedMember on the other hand sends it through the replicator
The MDReplicatedCommandReplicator is slightly different
To allow support for data converters and for the value change event we would need to modify the MDReplicatedMember to send its messages through the replicator just like MDClockedReplicatedMember does. In addition it should be noted that the MDReplicatedCommandReplicator supports both GameClock and no-GameClock modes in the same class. This is would also be possible for MDReplicatedMember if we send the commands through the MDReplicator.
Suggested Solution
I propose that we redo the replicated members so we end up with the following end result
MDReplicatedMember
MDRInterpolatedVector2
MDReplicatedCommandReplicator
MDList
Benefits of this change
Example of how a class could be it's own data converter and thus be replicated. You can note there is no need to set the data converter setting since the interface is implemented directly in the class. This change would need to be made for the MDList as well.