We no longer update owner variables to observers

This commit is contained in:
Paul Pacheco 2018-08-01 15:24:35 -05:00
parent 50df4d1b1f
commit 78e8a44397
3 changed files with 221 additions and 65 deletions

View File

@ -25,7 +25,7 @@ public class NetworkBehaviour : MonoBehaviour
public NetworkConnection connectionToServer { get { return myView.connectionToServer; } }
public NetworkConnection connectionToClient { get { return myView.connectionToClient; } }
public short playerControllerId { get { return myView.playerControllerId; } }
protected ulong syncVarDirtyBits { get { return m_SyncVarDirtyBits; } }
public ulong syncVarDirtyBits { get { return m_SyncVarDirtyBits; } set { m_SyncVarDirtyBits = value; } }
protected bool syncVarHookGuard { get { return m_SyncVarGuard; } set { m_SyncVarGuard = value; }}
// determine which variables are SyncToOwner
// to get dirty owners, we do syncVarDirtyBits & syncVarOwnerMask
@ -548,6 +548,11 @@ public void ClearAllDirtyBits()
m_SyncVarDirtyBits = 0L;
}
public void ClearOwnerDirtyBits()
{
m_SyncVarDirtyBits = m_SyncVarDirtyBits & (~syncVarOwnerMask);
}
public void SetAllDirtyBits()
{
m_LastSendTime = float.MinValue;

View File

@ -443,9 +443,31 @@ internal bool OnSerializeSafely(NetworkBehaviour comp, NetworkWriter writer, boo
return result;
}
internal void ClearDirtyBits(bool all= false)
{
foreach (NetworkBehaviour comp in m_NetworkBehaviours)
{
// we only want to clear the ones we just sent
// otherwise we would be resetting the components waiting for their timer
// waiting for their turn.
if (comp.IsDirty() || all)
{
comp.ClearAllDirtyBits();
}
}
}
internal void SetAllDirtyBits()
{
foreach(NetworkBehaviour comp in m_NetworkBehaviours)
{
comp.SetAllDirtyBits();
}
}
// serialize all components (or only dirty ones for channelId if not initial state)
// -> returns TRUE if any date other than dirtyMask was written!
internal bool OnSerializeAllSafely(NetworkBehaviour[] components, NetworkWriter writer, bool initialState, int channelId)
internal bool OnSerializeAllSafely(NetworkBehaviour[] components, NetworkWriter writer, bool initialState, SyncTarget target, int channelId)
{
if (components.Length > 64)
{
@ -462,20 +484,25 @@ internal bool OnSerializeAllSafely(NetworkBehaviour[] components, NetworkWriter
// -> always serialize if initialState so all components with all channels are included in spawn packet
// -> note: IsDirty() is false if the component isn't dirty or sendInterval isn't elapsed yet
NetworkBehaviour comp = m_NetworkBehaviours[i];
if (initialState || (comp.IsDirty() && comp.GetNetworkChannel() == channelId))
ulong dirtyBits = comp.syncVarDirtyBits;
if (target == SyncTarget.Observers)
{
// if we are synchronizing for observers, all owner variables are treated as clean
comp.ClearOwnerDirtyBits();
}
if (comp.IsDirty() && comp.GetNetworkChannel() == channelId)
{
// set bit #i to 1 in dirty mask
dirtyComponentsMask |= (ulong)(1L << i);
if (initialState)
{
comp.SetAllDirtyBits();
}
// serialize and clear dirty bits in any case, since the component was clearly dirty if we got here
if (LogFilter.logDebug) { Debug.Log("OnSerializeAllSafely: " + name + " -> " + comp.GetType() + " initial=" + initialState + " channelId=" + channelId); }
OnSerializeSafely(comp, payload, initialState);
comp.ClearAllDirtyBits();
}
// restory the dirty bits, serialization should not have side effec
comp.syncVarDirtyBits = dirtyBits;
}
// did we write anything? then write dirty, payload and return true
@ -492,7 +519,7 @@ internal bool OnSerializeAllSafely(NetworkBehaviour[] components, NetworkWriter
}
// extra version that uses m_NetworkBehaviours so we can call it from the outside
internal void OnSerializeAllSafely(NetworkWriter writer, bool initialState, int channelId) { OnSerializeAllSafely(m_NetworkBehaviours, writer, initialState, channelId); }
internal void OnSerializeAllSafely(NetworkWriter writer, bool initialState, SyncTarget target, int channelId) { OnSerializeAllSafely(m_NetworkBehaviours, writer, initialState, target, channelId); }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -746,23 +773,78 @@ internal void UNetUpdate()
// go through each channel
for (int channelId = 0; channelId < NetworkServer.numChannels; channelId++)
{
// serialize all the dirty components and send (if any were dirty)
NetworkWriter writer = new NetworkWriter();
if (OnSerializeAllSafely(m_NetworkBehaviours, writer, false, channelId))
SendUpdateVarsMessage(channelId, SyncTarget.Owner);
SendUpdateVarsMessage(channelId, SyncTarget.Observers);
}
// reset dirty bits for everything that was sent
ClearDirtyBits();
}
// sends a message to all observers except the owner
public int SendToObservers(short msgType, MessageBase msg, int channelId)
{
int count = 0;
for (int i = 0; i < observers.Count; ++i)
{
NetworkConnection conn = observers[i];
if (conn.isReady && conn != m_ClientAuthorityOwner)
{
if (conn.SendByChannel(msgType, msg, channelId))
count++;
}
}
return count;
}
// returns true if there are no non owner observers
public bool HasNonOwnerObserver()
{
return observers.Any(conn => conn != m_ClientAuthorityOwner);
}
public void SendToOwner(short msgType, MessageBase msg, int channelId)
{
m_ClientAuthorityOwner.SendByChannel(msgType, msg, channelId);
}
private bool SendUpdateVarsMessage(int channelId, SyncTarget target)
{
if (m_ClientAuthorityOwner == null && target == SyncTarget.Owner)
{
// there is no owner
return false;
}
// serialize all the dirty components and send (if any were dirty)
NetworkWriter writer = new NetworkWriter();
if (OnSerializeAllSafely(m_NetworkBehaviours, writer, false, target, channelId))
{
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Outgoing,
(short)MsgType.UpdateVars, name, 1);
#endif
// construct message and send
UpdateVarsMessage message = new UpdateVarsMessage();
message.netId = netId;
message.payload = writer.ToArray();
// construct message and send
UpdateVarsMessage message = new UpdateVarsMessage();
message.netId = netId;
message.payload = writer.ToArray();
NetworkServer.SendByChannelToReady(gameObject, (short)MsgType.UpdateVars, message, channelId);
if (target == SyncTarget.Owner)
{
SendToOwner((short)MsgType.UpdateVars, message, channelId);
}
else
{
SendToObservers((short)MsgType.UpdateVars, message, channelId);
}
if (LogFilter.logDev) { Debug.Log("Synchronized data for " + target + ", data size = " + message.payload.Length); }
return true;
}
return false;
}
internal void OnUpdateVars(NetworkReader reader, bool initialState)
@ -1076,7 +1158,6 @@ internal void Reset()
m_NetworkBehaviours = null;
ClearObservers();
m_ClientAuthorityOwner = null;
}
#if UNITY_EDITOR

View File

@ -739,11 +739,18 @@ static internal bool InternalAddPlayerForConnection(NetworkConnection conn, Game
if (LogFilter.logDebug) { Debug.Log("Adding new playerGameObject object netId: " + playerGameObject.GetComponent<NetworkIdentity>().netId + " asset ID " + playerGameObject.GetComponent<NetworkIdentity>().assetId); }
FinishPlayerForConnection(conn, playerNetworkIdentity, playerGameObject);
// paul: Need to set owner before sending spawn message so we can avoid sending owner variables
if (playerNetworkIdentity.localPlayerAuthority)
{
playerNetworkIdentity.SetClientOwner(conn);
}
else
{
playerNetworkIdentity.SetClientOwner(null);
}
FinishPlayerForConnection(conn, playerNetworkIdentity, playerGameObject);
return true;
}
@ -783,11 +790,15 @@ static bool SetupLocalPlayerForConnection(NetworkConnection conn, NetworkIdentit
uv.OnStartServer(true);
}
uv.RebuildObservers(true);
// paul: set the owner before sending the spawn message
// so that we can avoid sending owner variables
uv.SetClientOwner(conn);
SendSpawnMessage(uv, null);
// Set up local player instance on the client instance and update local object map
localConnection.localClient.AddLocalPlayer(newPlayerController);
uv.SetClientOwner(conn);
// Trigger OnAuthority
uv.ForceAuthority(true);
@ -854,11 +865,19 @@ static internal bool InternalReplacePlayerForConnection(NetworkConnection conn,
if (LogFilter.logDebug) { Debug.Log("Replacing playerGameObject object netId: " + playerGameObject.GetComponent<NetworkIdentity>().netId + " asset ID " + playerGameObject.GetComponent<NetworkIdentity>().assetId); }
FinishPlayerForConnection(conn, playerNetworkIdentity, playerGameObject);
// paul: Need to set owner before sending spawn message so we can avoid sending owner variables
if (playerNetworkIdentity.localPlayerAuthority)
{
playerNetworkIdentity.SetClientOwner(conn);
}
else
{
playerNetworkIdentity.SetClientOwner(null);
}
FinishPlayerForConnection(conn, playerNetworkIdentity, playerGameObject);
return true;
}
@ -1092,69 +1111,120 @@ static internal void SendSpawnMessage(NetworkIdentity uv, NetworkConnection conn
if (uv.serverOnly)
return;
if (LogFilter.logDebug) { Debug.Log("Server SendSpawnMessage: name=" + uv.name + " sceneId=" + uv.sceneId + " netid=" + uv.netId); } // for easier debugging
//if (LogFilter.logDebug) { Debug.Log("Server SendSpawnMessage: name=" + uv.name + " sceneId=" + uv.sceneId + " netid=" + uv.netId + " owner = " + (uv.clientAuthorityOwner != null)); } // for easier debugging
bool sendToOwner = uv.clientAuthorityOwner != null && (conn == null || uv.clientAuthorityOwner == conn);
bool sendToObserver = (conn == null || uv.clientAuthorityOwner != conn);
int messageCount = 0;
// everything is dirty during spawning
uv.SetAllDirtyBits();
// 'uv' is a prefab that should be spawned
if (uv.sceneId.IsEmpty())
{
SpawnPrefabMessage msg = new SpawnPrefabMessage();
msg.netId = uv.netId;
msg.assetId = uv.assetId;
msg.position = uv.transform.position;
msg.rotation = uv.transform.rotation;
// serialize all components with initialState = true
NetworkWriter writer = new NetworkWriter();
uv.OnSerializeAllSafely(writer, true, -1); // channelId doesn't matter if initialState
msg.payload = writer.ToArray();
// conn is != null when spawning it for a client
if (conn != null)
if (sendToOwner)
{
conn.Send((short)MsgType.SpawnPrefab, msg);
if (LogFilter.logDebug) { Debug.Log("Server SendSpawnMessage: name=" + uv.name + " sceneId=" + uv.sceneId + " netid=" + uv.netId + " to owner=" + uv.clientAuthorityOwner.connectionId); } // for easier debugging
messageCount += SendSpanPrefabMessage(uv, uv.clientAuthorityOwner, SyncTarget.Owner);
}
// conn is == null when spawning it for the local player
else
if (sendToObserver)
{
SendToReady(uv.gameObject, (short)MsgType.SpawnPrefab, msg);
if (LogFilter.logDebug) { Debug.Log("Server SendSpawnMessage: name=" + uv.name + " sceneId=" + uv.sceneId + " netid=" + uv.netId + " to observers"); } // for easier debugging
messageCount += SendSpanPrefabMessage(uv, conn, SyncTarget.Observers);
}
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Outgoing,
(short)MsgType.SpawnPrefab, uv.assetId.ToString(), 1);
#endif
}
// 'uv' is a scene object that should be spawned again
else
{
SpawnSceneObjectMessage msg = new SpawnSceneObjectMessage();
msg.netId = uv.netId;
msg.sceneId = uv.sceneId;
msg.position = uv.transform.position;
// include synch data
NetworkWriter writer = new NetworkWriter();
uv.OnSerializeAllSafely(writer, true, -1); // channelId doesn't matter if initialState
msg.payload = writer.ToArray();
// conn is != null when spawning it for a client
if (conn != null)
if (sendToOwner)
{
conn.Send((short)MsgType.SpawnSceneObject, msg);
if (LogFilter.logDebug) { Debug.Log("Server SendSpawnSceneObjectMessage: name=" + uv.name + " sceneId=" + uv.sceneId + " netid=" + uv.netId + " to owner=" + uv.clientAuthorityOwner.connectionId); } // for easier debugging
messageCount += SendSpawnSceneObjectMessage(uv, uv.clientAuthorityOwner, SyncTarget.Owner);
}
// conn is == null when spawning it for the local player
else
if (sendToObserver)
{
SendToReady(uv.gameObject, (short)MsgType.SpawnSceneObject, msg);
if (LogFilter.logDebug) { Debug.Log("Server SendSpawnSceneObjectMessage: name=" + uv.name + " sceneId=" + uv.sceneId + " netid=" + uv.netId + " to observers"); } // for easier debugging
messageCount += SendSpawnSceneObjectMessage(uv, conn, SyncTarget.Observers);
}
}
// if we just spawned for everybody, clear all dirty bits
if (messageCount >= uv.observers.Count)
uv.ClearDirtyBits(true);
}
private static int SendSpawnSceneObjectMessage(NetworkIdentity uv, NetworkConnection conn, SyncTarget target)
{
SpawnSceneObjectMessage msg = new SpawnSceneObjectMessage();
msg.netId = uv.netId;
msg.sceneId = uv.sceneId;
msg.position = uv.transform.position;
// include synch data
NetworkWriter writer = new NetworkWriter();
uv.OnSerializeAllSafely(writer, true, SyncTarget.Owner, -1); // channelId doesn't matter if initialState
msg.payload = writer.ToArray();
int sentCount = 0;
// conn is != null when spawning it for a client
if (conn != null)
{
if (conn.SendByChannel((short)MsgType.SpawnSceneObject, msg, Channels.DefaultReliable))
sentCount++;
}
// conn is == null when spawning it for the local player
else
{
sentCount += uv.SendToObservers((short)MsgType.SpawnSceneObject, msg, Channels.DefaultReliable);
}
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Outgoing,
(short)MsgType.SpawnSceneObject, "sceneId", 1);
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Outgoing,
(short)MsgType.SpawnSceneObject, "sceneId", 1);
#endif
return sentCount;
}
private static int SendSpanPrefabMessage(NetworkIdentity uv, NetworkConnection conn, SyncTarget target)
{
SpawnPrefabMessage msg = new SpawnPrefabMessage();
msg.netId = uv.netId;
msg.assetId = uv.assetId;
msg.position = uv.transform.position;
msg.rotation = uv.transform.rotation;
// serialize all components with initialState = true
NetworkWriter writer = new NetworkWriter();
uv.OnSerializeAllSafely(writer, true, target, -1); // channelId doesn't matter if initialState
msg.payload = writer.ToArray();
int sentCount = 0;
// conn is != null when spawning it for a client
if (conn != null)
{
if (conn.SendByChannel((short)MsgType.SpawnPrefab, msg, Channels.DefaultReliable))
sentCount++;
}
// conn is == null when spawning it for the local player
else
{
sentCount+= uv.SendToObservers((short)MsgType.SpawnPrefab, msg, Channels.DefaultReliable);
}
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Outgoing,
(short)MsgType.SpawnPrefab, uv.assetId.ToString(), 1);
#endif
return sentCount;
}
static public void DestroyPlayersForConnection(NetworkConnection conn)