mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-18 11:00:32 +00:00
Merge branch 'master' into DocUpdate919
This commit is contained in:
commit
49b3307477
@ -170,18 +170,25 @@ public override void OnInspectorGUI()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// only show SyncInterval if we have an OnSerialize function.
|
// does it sync anything? then show extra properties
|
||||||
// No need to show it if the class only has Cmds/Rpcs and no sync.
|
// (no need to show it if the class only has Cmds/Rpcs and no sync)
|
||||||
if (syncsAnything)
|
if (syncsAnything)
|
||||||
{
|
{
|
||||||
NetworkBehaviour networkBehaviour = target as NetworkBehaviour;
|
NetworkBehaviour networkBehaviour = target as NetworkBehaviour;
|
||||||
if (networkBehaviour != null)
|
if (networkBehaviour != null)
|
||||||
{
|
{
|
||||||
|
// syncMode
|
||||||
|
serializedObject.FindProperty("syncMode").enumValueIndex = (int)(SyncMode)
|
||||||
|
EditorGUILayout.EnumPopup("Network Sync Mode", networkBehaviour.syncMode);
|
||||||
|
|
||||||
|
// syncInterval
|
||||||
// [0,2] should be enough. anything >2s is too laggy anyway.
|
// [0,2] should be enough. anything >2s is too laggy anyway.
|
||||||
serializedObject.FindProperty("syncInterval").floatValue = EditorGUILayout.Slider(
|
serializedObject.FindProperty("syncInterval").floatValue = EditorGUILayout.Slider(
|
||||||
new GUIContent("Network Sync Interval",
|
new GUIContent("Network Sync Interval",
|
||||||
"Time in seconds until next change is synchronized to the client. '0' means send immediately if changed. '0.5' means only send changes every 500ms.\n(This is for state synchronization like SyncVars, SyncLists, OnSerialize. Not for Cmds, Rpcs, etc.)"),
|
"Time in seconds until next change is synchronized to the client. '0' means send immediately if changed. '0.5' means only send changes every 500ms.\n(This is for state synchronization like SyncVars, SyncLists, OnSerialize. Not for Cmds, Rpcs, etc.)"),
|
||||||
networkBehaviour.syncInterval, 0, 2);
|
networkBehaviour.syncInterval, 0, 2);
|
||||||
|
|
||||||
|
// apply
|
||||||
serializedObject.ApplyModifiedProperties();
|
serializedObject.ApplyModifiedProperties();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,11 @@
|
|||||||
|
|
||||||
namespace Mirror
|
namespace Mirror
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Sync to everyone, or only to owner.
|
||||||
|
/// </summary>
|
||||||
|
public enum SyncMode { Observers, Owner }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base class which should be inherited by scripts which contain networking functionality.
|
/// Base class which should be inherited by scripts which contain networking functionality.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -19,6 +24,12 @@ public class NetworkBehaviour : MonoBehaviour
|
|||||||
{
|
{
|
||||||
float lastSyncTime;
|
float lastSyncTime;
|
||||||
|
|
||||||
|
// hidden because NetworkBehaviourInspector shows it only if has OnSerialize.
|
||||||
|
/// <summary>
|
||||||
|
/// sync mode for OnSerialize
|
||||||
|
/// </summary>
|
||||||
|
[HideInInspector] public SyncMode syncMode = SyncMode.Observers;
|
||||||
|
|
||||||
// hidden because NetworkBehaviourInspector shows it only if has OnSerialize.
|
// hidden because NetworkBehaviourInspector shows it only if has OnSerialize.
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// sync interval for OnSerialize (in seconds)
|
/// sync interval for OnSerialize (in seconds)
|
||||||
@ -321,7 +332,7 @@ protected void SendEventInternal(Type invokeClass, string eventName, NetworkWrit
|
|||||||
payload = writer.ToArraySegment() // segment to avoid reader allocations
|
payload = writer.ToArraySegment() // segment to avoid reader allocations
|
||||||
};
|
};
|
||||||
|
|
||||||
NetworkServer.SendToReady(netIdentity,message, channelId);
|
NetworkServer.SendToReady(netIdentity, message, channelId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -676,20 +676,38 @@ bool OnSerializeSafely(NetworkBehaviour comp, NetworkWriter writer, bool initial
|
|||||||
}
|
}
|
||||||
|
|
||||||
// serialize all components (or only dirty ones if not initial state)
|
// serialize all components (or only dirty ones if not initial state)
|
||||||
// -> returns true if something was written
|
// -> check ownerWritten/observersWritten to know if anything was written
|
||||||
internal bool OnSerializeAllSafely(bool initialState, NetworkWriter writer)
|
internal void OnSerializeAllSafely(bool initialState, NetworkWriter ownerWriter, out int ownerWritten, NetworkWriter observersWriter, out int observersWritten)
|
||||||
{
|
{
|
||||||
|
// clear 'written' variables
|
||||||
|
ownerWritten = observersWritten = 0;
|
||||||
|
|
||||||
if (NetworkBehaviours.Length > 64)
|
if (NetworkBehaviours.Length > 64)
|
||||||
{
|
{
|
||||||
Debug.LogError("Only 64 NetworkBehaviour components are allowed for NetworkIdentity: " + name + " because of the dirtyComponentMask");
|
Debug.LogError("Only 64 NetworkBehaviour components are allowed for NetworkIdentity: " + name + " because of the dirtyComponentMask");
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
ulong dirtyComponentsMask = GetDirtyMask(initialState);
|
ulong dirtyComponentsMask = GetDirtyMask(initialState);
|
||||||
|
|
||||||
if (dirtyComponentsMask == 0L)
|
if (dirtyComponentsMask == 0L)
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
writer.WritePackedUInt64(dirtyComponentsMask); // WritePacked64 so we don't write full 8 bytes if we don't have to
|
// calculate syncMode mask at runtime. this allows users to change
|
||||||
|
// component.syncMode while the game is running, which can be a huge
|
||||||
|
// advantage over syncvar-based sync modes. e.g. if a player decides
|
||||||
|
// to share or not share his inventory, or to go invisible, etc.
|
||||||
|
//
|
||||||
|
// (this also lets the TestSynchronizingObjects test pass because
|
||||||
|
// otherwise if we were to cache it in Awake, then we would call
|
||||||
|
// GetComponents<NetworkBehaviour> before all the test behaviours
|
||||||
|
// were added)
|
||||||
|
ulong syncModeObserversMask = GetSyncModeObserversMask();
|
||||||
|
|
||||||
|
// write regular dirty mask for owner,
|
||||||
|
// writer 'dirty mask & syncMode==Everyone' for everyone else
|
||||||
|
// (WritePacked64 so we don't write full 8 bytes if we don't have to)
|
||||||
|
ownerWriter.WritePackedUInt64(dirtyComponentsMask);
|
||||||
|
observersWriter.WritePackedUInt64(dirtyComponentsMask & syncModeObserversMask);
|
||||||
|
|
||||||
foreach (NetworkBehaviour comp in NetworkBehaviours)
|
foreach (NetworkBehaviour comp in NetworkBehaviours)
|
||||||
{
|
{
|
||||||
@ -698,13 +716,32 @@ internal bool OnSerializeAllSafely(bool initialState, NetworkWriter writer)
|
|||||||
// -> note: IsDirty() is false if the component isn't dirty or sendInterval isn't elapsed yet
|
// -> note: IsDirty() is false if the component isn't dirty or sendInterval isn't elapsed yet
|
||||||
if (initialState || comp.IsDirty())
|
if (initialState || comp.IsDirty())
|
||||||
{
|
{
|
||||||
// serialize the data
|
|
||||||
if (LogFilter.Debug) Debug.Log("OnSerializeAllSafely: " + name + " -> " + comp.GetType() + " initial=" + initialState);
|
if (LogFilter.Debug) Debug.Log("OnSerializeAllSafely: " + name + " -> " + comp.GetType() + " initial=" + initialState);
|
||||||
OnSerializeSafely(comp, writer, initialState);
|
|
||||||
|
// serialize into ownerWriter first
|
||||||
|
// (owner always gets everything!)
|
||||||
|
int startPosition = ownerWriter.Position;
|
||||||
|
OnSerializeSafely(comp, ownerWriter, initialState);
|
||||||
|
++ownerWritten;
|
||||||
|
|
||||||
|
// copy into observersWriter too if SyncMode.Observers
|
||||||
|
// -> we copy instead of calling OnSerialize again because
|
||||||
|
// we don't know what magic the user does in OnSerialize.
|
||||||
|
// -> it's not guaranteed that calling it twice gets the
|
||||||
|
// same result
|
||||||
|
// -> it's not guaranteed that calling it twice doesn't mess
|
||||||
|
// with the user's OnSerialize timing code etc.
|
||||||
|
// => so we just copy the result without touching
|
||||||
|
// OnSerialize again
|
||||||
|
if (comp.syncMode == SyncMode.Observers)
|
||||||
|
{
|
||||||
|
ArraySegment<byte> segment = ownerWriter.ToArraySegment();
|
||||||
|
int length = ownerWriter.Position - startPosition;
|
||||||
|
observersWriter.WriteBytes(segment.Array, startPosition, length);
|
||||||
|
++observersWritten;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal ulong GetDirtyMask(bool initialState)
|
internal ulong GetDirtyMask(bool initialState)
|
||||||
@ -724,6 +761,24 @@ internal ulong GetDirtyMask(bool initialState)
|
|||||||
return dirtyComponentsMask;
|
return dirtyComponentsMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// a mask that contains all the components with SyncMode.Observers
|
||||||
|
internal ulong GetSyncModeObserversMask()
|
||||||
|
{
|
||||||
|
// loop through all components
|
||||||
|
ulong mask = 0UL;
|
||||||
|
NetworkBehaviour[] components = NetworkBehaviours;
|
||||||
|
for (int i = 0; i < NetworkBehaviours.Length; ++i)
|
||||||
|
{
|
||||||
|
NetworkBehaviour comp = components[i];
|
||||||
|
if (comp.syncMode == SyncMode.Observers)
|
||||||
|
{
|
||||||
|
mask |= 1UL << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
void OnDeserializeSafely(NetworkBehaviour comp, NetworkReader reader, bool initialState)
|
void OnDeserializeSafely(NetworkBehaviour comp, NetworkReader reader, bool initialState)
|
||||||
{
|
{
|
||||||
// read header as 4 bytes and calculate this chunk's start+end
|
// read header as 4 bytes and calculate this chunk's start+end
|
||||||
@ -1141,21 +1196,42 @@ internal void MirrorUpdate()
|
|||||||
{
|
{
|
||||||
if (observers != null && observers.Count > 0)
|
if (observers != null && observers.Count > 0)
|
||||||
{
|
{
|
||||||
NetworkWriter writer = NetworkWriterPool.GetWriter();
|
// one writer for owner, one for observers
|
||||||
|
NetworkWriter ownerWriter = NetworkWriterPool.GetWriter();
|
||||||
|
NetworkWriter observersWriter = NetworkWriterPool.GetWriter();
|
||||||
|
|
||||||
// serialize all the dirty components and send (if any were dirty)
|
// serialize all the dirty components and send (if any were dirty)
|
||||||
if (OnSerializeAllSafely(false, writer))
|
OnSerializeAllSafely(false, ownerWriter, out int ownerWritten, observersWriter, out int observersWritten);
|
||||||
|
if (ownerWritten > 0 || observersWritten > 0)
|
||||||
{
|
{
|
||||||
// populate cached UpdateVarsMessage and send
|
// populate cached UpdateVarsMessage and send
|
||||||
varsMessage.netId = netId;
|
varsMessage.netId = netId;
|
||||||
// segment to avoid reader allocations.
|
|
||||||
// (never null because of our above check)
|
// send ownerWriter to owner
|
||||||
varsMessage.payload = writer.ToArraySegment();
|
// (only if we serialized anything for owner)
|
||||||
NetworkServer.SendToReady(this, varsMessage);
|
// (only if there is a connection (e.g. if not a monster),
|
||||||
|
// and if connection is ready because we use SendToReady
|
||||||
|
// below too)
|
||||||
|
if (ownerWritten > 0)
|
||||||
|
{
|
||||||
|
varsMessage.payload = ownerWriter.ToArraySegment();
|
||||||
|
if (connectionToClient != null && connectionToClient.isReady)
|
||||||
|
NetworkServer.SendToClientOfPlayer(this, varsMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// send observersWriter to everyone but owner
|
||||||
|
// (only if we serialized anything for observers)
|
||||||
|
if (observersWritten > 0)
|
||||||
|
{
|
||||||
|
varsMessage.payload = observersWriter.ToArraySegment();
|
||||||
|
NetworkServer.SendToReady(this, varsMessage, false);
|
||||||
|
}
|
||||||
|
|
||||||
// only clear bits if we sent something
|
// only clear bits if we sent something
|
||||||
ClearDirtyBits();
|
ClearDirtyBits();
|
||||||
}
|
}
|
||||||
NetworkWriterPool.Recycle(writer);
|
NetworkWriterPool.Recycle(ownerWriter);
|
||||||
|
NetworkWriterPool.Recycle(observersWriter);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -333,9 +333,10 @@ public static bool SendToReady(NetworkIdentity identity, short msgType, MessageB
|
|||||||
/// <typeparam name="T">Message type.</typeparam>
|
/// <typeparam name="T">Message type.</typeparam>
|
||||||
/// <param name="identity"></param>
|
/// <param name="identity"></param>
|
||||||
/// <param name="msg">Message structure.</param>
|
/// <param name="msg">Message structure.</param>
|
||||||
|
/// <param name="includeSelf">Send to observers including self..</param>
|
||||||
/// <param name="channelId">Transport channel to use</param>
|
/// <param name="channelId">Transport channel to use</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static bool SendToReady<T>(NetworkIdentity identity,T msg, int channelId = Channels.DefaultReliable) where T : IMessageBase
|
public static bool SendToReady<T>(NetworkIdentity identity, T msg, bool includeSelf = true, int channelId = Channels.DefaultReliable) where T : IMessageBase
|
||||||
{
|
{
|
||||||
if (LogFilter.Debug) Debug.Log("Server.SendToReady msgType:" + typeof(T));
|
if (LogFilter.Debug) Debug.Log("Server.SendToReady msgType:" + typeof(T));
|
||||||
|
|
||||||
@ -347,7 +348,9 @@ public static bool SendToReady<T>(NetworkIdentity identity,T msg, int channelId
|
|||||||
bool result = true;
|
bool result = true;
|
||||||
foreach (KeyValuePair<int, NetworkConnection> kvp in identity.observers)
|
foreach (KeyValuePair<int, NetworkConnection> kvp in identity.observers)
|
||||||
{
|
{
|
||||||
if (kvp.Value.isReady)
|
bool isSelf = kvp.Value == identity.connectionToClient;
|
||||||
|
if ((!isSelf || includeSelf) &&
|
||||||
|
kvp.Value.isReady)
|
||||||
{
|
{
|
||||||
result &= kvp.Value.SendBytes(bytes, channelId);
|
result &= kvp.Value.SendBytes(bytes, channelId);
|
||||||
}
|
}
|
||||||
@ -357,6 +360,20 @@ public static bool SendToReady<T>(NetworkIdentity identity,T msg, int channelId
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Send a message structure with the given type number to only clients which are ready.
|
||||||
|
/// <para>See Networking.NetworkClient.Ready.</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Message type.</typeparam>
|
||||||
|
/// <param name="identity"></param>
|
||||||
|
/// <param name="msg">Message structure.</param>
|
||||||
|
/// <param name="channelId">Transport channel to use</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool SendToReady<T>(NetworkIdentity identity, T msg, int channelId = Channels.DefaultReliable) where T : IMessageBase
|
||||||
|
{
|
||||||
|
return SendToReady(identity, msg, true, channelId);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Disconnect all currently connected clients, including the local connection.
|
/// Disconnect all currently connected clients, including the local connection.
|
||||||
/// <para>This can only be called on the server. Clients will receive the Disconnect message.</para>
|
/// <para>This can only be called on the server. Clients will receive the Disconnect message.</para>
|
||||||
@ -1009,18 +1026,19 @@ internal static void SendSpawnMessage(NetworkIdentity identity, NetworkConnectio
|
|||||||
|
|
||||||
if (LogFilter.Debug) Debug.Log("Server SendSpawnMessage: name=" + identity.name + " sceneId=" + identity.sceneId.ToString("X") + " netid=" + identity.netId); // for easier debugging
|
if (LogFilter.Debug) Debug.Log("Server SendSpawnMessage: name=" + identity.name + " sceneId=" + identity.sceneId.ToString("X") + " netid=" + identity.netId); // for easier debugging
|
||||||
|
|
||||||
NetworkWriter writer = NetworkWriterPool.GetWriter();
|
// one writer for owner, one for observers
|
||||||
|
NetworkWriter ownerWriter = NetworkWriterPool.GetWriter();
|
||||||
|
NetworkWriter observersWriter = NetworkWriterPool.GetWriter();
|
||||||
|
|
||||||
// convert to ArraySegment to avoid reader allocations
|
|
||||||
// (need to handle null case too)
|
|
||||||
ArraySegment<byte> segment = default;
|
|
||||||
|
|
||||||
// serialize all components with initialState = true
|
// serialize all components with initialState = true
|
||||||
// (can be null if has none)
|
// (can be null if has none)
|
||||||
if (identity.OnSerializeAllSafely(true, writer))
|
identity.OnSerializeAllSafely(true, ownerWriter, out int ownerWritten, observersWriter, out int observersWritten);
|
||||||
{
|
|
||||||
segment = writer.ToArraySegment();
|
// convert to ArraySegment to avoid reader allocations
|
||||||
}
|
// (need to handle null case too)
|
||||||
|
ArraySegment<byte> ownerSegment = ownerWritten > 0 ? ownerWriter.ToArraySegment() : default;
|
||||||
|
ArraySegment<byte> observersSegment = observersWritten > 0 ? observersWriter.ToArraySegment() : default;
|
||||||
|
|
||||||
// 'identity' is a prefab that should be spawned
|
// 'identity' is a prefab that should be spawned
|
||||||
if (identity.sceneId == 0)
|
if (identity.sceneId == 0)
|
||||||
@ -1033,19 +1051,35 @@ internal static void SendSpawnMessage(NetworkIdentity identity, NetworkConnectio
|
|||||||
// use local values for VR support
|
// use local values for VR support
|
||||||
position = identity.transform.localPosition,
|
position = identity.transform.localPosition,
|
||||||
rotation = identity.transform.localRotation,
|
rotation = identity.transform.localRotation,
|
||||||
scale = identity.transform.localScale,
|
scale = identity.transform.localScale
|
||||||
payload = segment
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// conn is != null when spawning it for a client
|
// conn is != null when spawning it for a client
|
||||||
if (conn != null)
|
if (conn != null)
|
||||||
{
|
{
|
||||||
|
// use owner segment if 'conn' owns this identity, otherwise
|
||||||
|
// use observers segment
|
||||||
|
bool isOwner = identity.connectionToClient == conn;
|
||||||
|
msg.payload = isOwner ? ownerSegment : observersSegment;
|
||||||
|
|
||||||
conn.Send(msg);
|
conn.Send(msg);
|
||||||
}
|
}
|
||||||
// conn is == null when spawning it for the local player
|
// conn is == null when spawning it for the local player
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SendToReady(identity, msg);
|
// send ownerWriter to owner
|
||||||
|
// (spawn no matter what, even if no components were
|
||||||
|
// serialized because the spawn message contains more data.
|
||||||
|
// components might still be updated later on.)
|
||||||
|
msg.payload = ownerSegment;
|
||||||
|
SendToClientOfPlayer(identity, msg);
|
||||||
|
|
||||||
|
// send observersWriter to everyone but owner
|
||||||
|
// (spawn no matter what, even if no components were
|
||||||
|
// serialized because the spawn message contains more data.
|
||||||
|
// components might still be updated later on.)
|
||||||
|
msg.payload = observersSegment;
|
||||||
|
SendToReady(identity, msg, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 'identity' is a scene object that should be spawned again
|
// 'identity' is a scene object that should be spawned again
|
||||||
@ -1059,23 +1093,40 @@ internal static void SendSpawnMessage(NetworkIdentity identity, NetworkConnectio
|
|||||||
// use local values for VR support
|
// use local values for VR support
|
||||||
position = identity.transform.localPosition,
|
position = identity.transform.localPosition,
|
||||||
rotation = identity.transform.localRotation,
|
rotation = identity.transform.localRotation,
|
||||||
scale = identity.transform.localScale,
|
scale = identity.transform.localScale
|
||||||
payload = segment
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// conn is != null when spawning it for a client
|
// conn is != null when spawning it for a client
|
||||||
if (conn != null)
|
if (conn != null)
|
||||||
{
|
{
|
||||||
|
// use owner segment if 'conn' owns this identity, otherwise
|
||||||
|
// use observers segment
|
||||||
|
bool isOwner = identity.connectionToClient == conn;
|
||||||
|
msg.payload = isOwner ? ownerSegment : observersSegment;
|
||||||
|
|
||||||
conn.Send(msg);
|
conn.Send(msg);
|
||||||
}
|
}
|
||||||
// conn is == null when spawning it for the local player
|
// conn is == null when spawning it for the local player
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SendToReady(identity, msg);
|
// send ownerWriter to owner
|
||||||
|
// (spawn no matter what, even if no components were
|
||||||
|
// serialized because the spawn message contains more data.
|
||||||
|
// components might still be updated later on.)
|
||||||
|
msg.payload = ownerSegment;
|
||||||
|
SendToClientOfPlayer(identity, msg);
|
||||||
|
|
||||||
|
// send observersWriter to everyone but owner
|
||||||
|
// (spawn no matter what, even if no components were
|
||||||
|
// serialized because the spawn message contains more data.
|
||||||
|
// components might still be updated later on.)
|
||||||
|
msg.payload = observersSegment;
|
||||||
|
SendToReady(identity, msg, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkWriterPool.Recycle(writer);
|
NetworkWriterPool.Recycle(ownerWriter);
|
||||||
|
NetworkWriterPool.Recycle(observersWriter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -65,8 +65,9 @@ public void TestSynchronizingObjects()
|
|||||||
player1.guild = myGuild;
|
player1.guild = myGuild;
|
||||||
|
|
||||||
// serialize all the data as we would for the network
|
// serialize all the data as we would for the network
|
||||||
NetworkWriter writer = new NetworkWriter();
|
NetworkWriter ownerWriter = new NetworkWriter();
|
||||||
identity1.OnSerializeAllSafely(true, writer);
|
NetworkWriter observersWriter = new NetworkWriter(); // not really used in this Test
|
||||||
|
identity1.OnSerializeAllSafely(true, ownerWriter, out int ownerWritten, observersWriter, out int observersWritten);
|
||||||
|
|
||||||
// set up a "client" object
|
// set up a "client" object
|
||||||
GameObject gameObject2 = new GameObject();
|
GameObject gameObject2 = new GameObject();
|
||||||
@ -74,11 +75,31 @@ public void TestSynchronizingObjects()
|
|||||||
MockPlayer player2 = gameObject2.AddComponent<MockPlayer>();
|
MockPlayer player2 = gameObject2.AddComponent<MockPlayer>();
|
||||||
|
|
||||||
// apply all the data from the server object
|
// apply all the data from the server object
|
||||||
NetworkReader reader = new NetworkReader(writer.ToArray());
|
NetworkReader reader = new NetworkReader(ownerWriter.ToArray());
|
||||||
identity2.OnDeserializeAllSafely(reader, true);
|
identity2.OnDeserializeAllSafely(reader, true);
|
||||||
|
|
||||||
// check that the syncvars got updated
|
// check that the syncvars got updated
|
||||||
Assert.That(player2.guild.name, Is.EqualTo("Back street boys"), "Data should be synchronized");
|
Assert.That(player2.guild.name, Is.EqualTo("Back street boys"), "Data should be synchronized");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSyncModeObserversMask()
|
||||||
|
{
|
||||||
|
GameObject gameObject1 = new GameObject();
|
||||||
|
NetworkIdentity identity = gameObject1.AddComponent<NetworkIdentity>();
|
||||||
|
MockPlayer player1 = gameObject1.AddComponent<MockPlayer>();
|
||||||
|
player1.syncInterval = 0;
|
||||||
|
MockPlayer player2 = gameObject1.AddComponent<MockPlayer>();
|
||||||
|
player2.syncInterval = 0;
|
||||||
|
MockPlayer player3 = gameObject1.AddComponent<MockPlayer>();
|
||||||
|
player3.syncInterval = 0;
|
||||||
|
|
||||||
|
// sync mode
|
||||||
|
player1.syncMode = SyncMode.Observers;
|
||||||
|
player2.syncMode = SyncMode.Owner;
|
||||||
|
player3.syncMode = SyncMode.Observers;
|
||||||
|
|
||||||
|
Assert.That(identity.GetSyncModeObserversMask(), Is.EqualTo(0b101));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,9 @@ What previously required **10.000** lines of code, now takes **1.000** lines of
|
|||||||
_Note: Mirror is based on Unity's abandoned UNET Networking system. We fixed it up and pushed it to MMO Scale._
|
_Note: Mirror is based on Unity's abandoned UNET Networking system. We fixed it up and pushed it to MMO Scale._
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
Check out our [Documentation](https://vis2k.github.io/Mirror/).
|
Check out our [Documentation](https://mirror-networking.com/xmldocs/).
|
||||||
|
|
||||||
If you are migrating from UNET, then please check out our [Migration Guide](https://vis2k.github.io/Mirror/General/Migration). Don't panic, it's very easy and won't take more than 5 minutes.
|
If you are migrating from UNET, then please check out our [Migration Guide](https://mirror-networking.com/xmldocs/articles/General/Migration.html). Don't panic, it's very easy and won't take more than 5 minutes.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
We **recommend** to download the most **stable Mirror version** from the [Asset Store](https://www.assetstore.unity3d.com/#!/content/129321)!
|
We **recommend** to download the most **stable Mirror version** from the [Asset Store](https://www.assetstore.unity3d.com/#!/content/129321)!
|
||||||
|
Loading…
Reference in New Issue
Block a user