Merged master

This commit is contained in:
MrGadget1024 2023-01-30 07:31:42 -05:00
commit d6e81dc687
20 changed files with 144 additions and 124 deletions

View File

@ -57,12 +57,6 @@ void Update()
void UpdateServer() void UpdateServer()
{ {
// set dirty to trigger OnSerialize. either always, or only if changed.
// technically snapshot interpolation requires constant sending.
// however, with reliable it should be fine without constant sends.
if (!onlySyncOnChange || Changed(Construct()))
SetDirty();
// apply buffered snapshots IF client authority // apply buffered snapshots IF client authority
// -> in server authority, server moves the object // -> in server authority, server moves the object
// so no need to apply any snapshots there. // so no need to apply any snapshots there.
@ -91,6 +85,14 @@ void UpdateServer()
Apply(computed); Apply(computed);
} }
} }
// set dirty to trigger OnSerialize. either always, or only if changed.
// technically snapshot interpolation requires constant sending.
// however, with reliable it should be fine without constant sends.
//
// detect changes _after_ all changes were applied above.
if (!onlySyncOnChange || Changed(Construct()))
SetDirty();
} }
void UpdateClient() void UpdateClient()

View File

@ -1,6 +1,8 @@
// host mode related helper functions. // host mode related helper functions.
// usually they set up both server & client. // usually they set up both server & client.
// it's cleaner to keep them in one place, instead of only in server / client. // it's cleaner to keep them in one place, instead of only in server / client.
using System;
namespace Mirror namespace Mirror
{ {
public static class HostMode public static class HostMode
@ -39,19 +41,8 @@ public static void InvokeOnConnected()
((LocalConnectionToServer)NetworkClient.connection).QueueConnectedEvent(); ((LocalConnectionToServer)NetworkClient.connection).QueueConnectedEvent();
} }
// calls OnStartClient for all SERVER objects in host mode once. // DEPRECATED 2023-01-28
// client doesn't get spawn messages for those, so need to call manually. [Obsolete("ActivateHostScene did nothing, since identities all had .isClient set in NetworkServer.SpawnObjects.")]
// public because NetworkServer.ActivateHostScene was public before too. public static void ActivateHostScene() {}
public static void ActivateHostScene()
{
foreach (NetworkIdentity identity in NetworkServer.spawned.Values)
{
if (!identity.isClient)
{
// Debug.Log($"ActivateHostScene {identity.netId} {identity}");
NetworkClient.CheckForStartClient(identity);
}
}
}
} }
} }

View File

@ -598,7 +598,7 @@ public static bool SyncVarGameObjectEqual(GameObject newGameObject, uint netIdFi
uint newNetId = 0; uint newNetId = 0;
if (newGameObject != null) if (newGameObject != null)
{ {
if (newGameObject.TryGetComponent<NetworkIdentity>(out NetworkIdentity identity)) if (newGameObject.TryGetComponent(out NetworkIdentity identity))
{ {
newNetId = identity.netId; newNetId = identity.netId;
if (newNetId == 0) if (newNetId == 0)
@ -621,7 +621,7 @@ protected void SetSyncVarGameObject(GameObject newGameObject, ref GameObject gam
uint newNetId = 0; uint newNetId = 0;
if (newGameObject != null) if (newGameObject != null)
{ {
if (newGameObject.TryGetComponent<NetworkIdentity>(out NetworkIdentity identity)) if (newGameObject.TryGetComponent(out NetworkIdentity identity))
{ {
newNetId = identity.netId; newNetId = identity.netId;
if (newNetId == 0) if (newNetId == 0)

View File

@ -383,7 +383,13 @@ internal static void OnTransportDisconnected()
// Raise the event before changing ConnectState // Raise the event before changing ConnectState
// because 'active' depends on this during shutdown // because 'active' depends on this during shutdown
if (connection != null) OnDisconnectedEvent?.Invoke(); //
// previously OnDisconnected was only invoked if connection != null.
// however, if DNS resolve fails in Transport.Connect(),
// OnDisconnected would never be called because 'connection' is only
// created after the Transport.Connect() call.
// fixes: https://github.com/MirrorNetworking/Mirror/issues/3365
OnDisconnectedEvent?.Invoke();
connectState = ConnectState.Disconnected; connectState = ConnectState.Disconnected;
ready = false; ready = false;
@ -572,7 +578,7 @@ public static void RegisterPrefab(GameObject prefab, uint newAssetId)
return; return;
} }
if (!prefab.TryGetComponent<NetworkIdentity>(out NetworkIdentity identity)) if (!prefab.TryGetComponent(out NetworkIdentity identity))
{ {
Debug.LogError($"Could not register '{prefab.name}' since it contains no NetworkIdentity component"); Debug.LogError($"Could not register '{prefab.name}' since it contains no NetworkIdentity component");
return; return;
@ -598,7 +604,7 @@ public static void RegisterPrefab(GameObject prefab)
return; return;
} }
if (!prefab.TryGetComponent<NetworkIdentity>(out NetworkIdentity identity)) if (!prefab.TryGetComponent(out NetworkIdentity identity))
{ {
Debug.LogError($"Could not register '{prefab.name}' since it contains no NetworkIdentity component"); Debug.LogError($"Could not register '{prefab.name}' since it contains no NetworkIdentity component");
return; return;
@ -634,7 +640,7 @@ public static void RegisterPrefab(GameObject prefab, SpawnDelegate spawnHandler,
return; return;
} }
if (!prefab.TryGetComponent<NetworkIdentity>(out NetworkIdentity identity)) if (!prefab.TryGetComponent(out NetworkIdentity identity))
{ {
Debug.LogError($"Could not register handler for '{prefab.name}' since it contains no NetworkIdentity component"); Debug.LogError($"Could not register handler for '{prefab.name}' since it contains no NetworkIdentity component");
return; return;
@ -681,7 +687,7 @@ public static void RegisterPrefab(GameObject prefab, uint newAssetId, SpawnHandl
return; return;
} }
if (!prefab.TryGetComponent<NetworkIdentity>(out NetworkIdentity identity)) if (!prefab.TryGetComponent(out NetworkIdentity identity))
{ {
Debug.LogError($"Could not register handler for '{prefab.name}' since it contains no NetworkIdentity component"); Debug.LogError($"Could not register handler for '{prefab.name}' since it contains no NetworkIdentity component");
return; return;
@ -747,7 +753,7 @@ public static void RegisterPrefab(GameObject prefab, SpawnHandlerDelegate spawnH
return; return;
} }
if (!prefab.TryGetComponent<NetworkIdentity>(out NetworkIdentity identity)) if (!prefab.TryGetComponent(out NetworkIdentity identity))
{ {
Debug.LogError($"Could not register handler for '{prefab.name}' since it contains no NetworkIdentity component"); Debug.LogError($"Could not register handler for '{prefab.name}' since it contains no NetworkIdentity component");
return; return;
@ -811,7 +817,7 @@ public static void UnregisterPrefab(GameObject prefab)
return; return;
} }
if (!prefab.TryGetComponent<NetworkIdentity>(out NetworkIdentity identity)) if (!prefab.TryGetComponent(out NetworkIdentity identity))
{ {
Debug.LogError($"Could not unregister '{prefab.name}' since it contains no NetworkIdentity component"); Debug.LogError($"Could not unregister '{prefab.name}' since it contains no NetworkIdentity component");
return; return;
@ -1011,12 +1017,25 @@ internal static void ApplySpawnPayload(NetworkIdentity identity, SpawnMessage me
identity.transform.localPosition = message.position; identity.transform.localPosition = message.position;
identity.transform.localRotation = message.rotation; identity.transform.localRotation = message.rotation;
identity.transform.localScale = message.scale; identity.transform.localScale = message.scale;
// configure flags
// the below DeserializeClient call invokes SyncVarHooks.
// flags always need to be initialized before that.
// fixes: https://github.com/MirrorNetworking/Mirror/issues/3259
identity.isOwned = message.isOwner; identity.isOwned = message.isOwner;
identity.netId = message.netId; identity.netId = message.netId;
if (message.isLocalPlayer) if (message.isLocalPlayer)
InternalAddPlayer(identity); InternalAddPlayer(identity);
// configure isClient/isLocalPlayer flags.
// => after InternalAddPlayer. can't initialize .isLocalPlayer
// before InternalAddPlayer sets .localPlayer
// => before DeserializeClient, otherwise SyncVar hooks wouldn't
// have isClient/isLocalPlayer set yet.
// fixes: https://github.com/MirrorNetworking/Mirror/issues/3259
InitializeIdentityFlags(identity);
// deserialize components if any payload // deserialize components if any payload
// (Count is 0 if there were no components) // (Count is 0 if there were no components)
if (message.payload.Count > 0) if (message.payload.Count > 0)
@ -1038,9 +1057,7 @@ internal static void ApplySpawnPayload(NetworkIdentity identity, SpawnMessage me
// here immediately since there won't be another OnObjectSpawnFinished. // here immediately since there won't be another OnObjectSpawnFinished.
if (isSpawnFinished) if (isSpawnFinished)
{ {
identity.NotifyAuthority(); InvokeIdentityCallbacks(identity);
CheckForStartClient(identity);
CheckForLocalPlayer(identity);
} }
} }
@ -1097,7 +1114,7 @@ static NetworkIdentity SpawnPrefab(SpawnMessage message)
return null; return null;
} }
if (!obj.TryGetComponent<NetworkIdentity>(out NetworkIdentity identity)) if (!obj.TryGetComponent(out NetworkIdentity identity))
{ {
Debug.LogError($"Object Spawned by handler did not have a NetworkIdentity, Handler assetId '{message.assetId}'"); Debug.LogError($"Object Spawned by handler did not have a NetworkIdentity, Handler assetId '{message.assetId}'");
return null; return null;
@ -1193,9 +1210,7 @@ internal static void OnObjectSpawnFinished(ObjectSpawnFinishedMessage _)
// they are destroyed. for safety, let's double check here. // they are destroyed. for safety, let's double check here.
if (identity != null) if (identity != null)
{ {
identity.NotifyAuthority(); BootstrapIdentity(identity);
CheckForStartClient(identity);
CheckForLocalPlayer(identity);
} }
else Debug.LogWarning("Found null entry in NetworkClient.spawned. This is unexpected. Was the NetworkIdentity not destroyed properly?"); else Debug.LogWarning("Found null entry in NetworkClient.spawned. This is unexpected. Was the NetworkIdentity not destroyed properly?");
} }
@ -1238,14 +1253,12 @@ internal static void OnHostClientSpawn(SpawnMessage message)
if (message.isLocalPlayer) if (message.isLocalPlayer)
InternalAddPlayer(identity); InternalAddPlayer(identity);
identity.isOwned = message.isOwner; // set visibility before invoking OnStartClient etc. callbacks
identity.NotifyAuthority();
CheckForStartClient(identity);
if (aoi != null) if (aoi != null)
aoi.SetHostVisibility(identity, true); aoi.SetHostVisibility(identity, true);
CheckForLocalPlayer(identity); identity.isOwned = message.isOwner;
BootstrapIdentity(identity);
} }
} }
@ -1340,43 +1353,58 @@ internal static void ChangeOwner(NetworkIdentity identity, ChangeOwnerMessage me
if (identity.isLocalPlayer) if (identity.isLocalPlayer)
{ {
localPlayer = identity; localPlayer = identity;
identity.connectionToServer = connection;
identity.OnStartLocalPlayer();
} }
// identity's isLocalPlayer was set to false. // identity's isLocalPlayer was set to false.
// clear our static localPlayer IF (and only IF) it was that one before. // clear our static localPlayer IF (and only IF) it was that one before.
else if (localPlayer == identity) else if (localPlayer == identity)
{ {
localPlayer = null; localPlayer = null;
// TODO set .connectionToServer to null for old local player?
// since we set it in the above 'if' case too.
} }
// call OnStartLocalPlayer if it's the local player now.
CheckForLocalPlayer(identity);
} }
// OnStartClient used to initialize isClient / isLocalPlayer. // set up NetworkIdentity flags on the client.
// it's cleaner to do this from NetworkClient. // needs to be separate from invoking callbacks.
internal static void CheckForStartClient(NetworkIdentity identity) // cleaner, and some places need to set flags first.
static void InitializeIdentityFlags(NetworkIdentity identity)
{ {
// OnStartLocalPlayer is called after OnStartClient. // initialize flags before invoking callbacks.
// but we want the flag to be set in OnStartClient already. // this way isClient/isLocalPlayer is correct during callbacks.
identity.isLocalPlayer = localPlayer == identity; // fixes: https://github.com/MirrorNetworking/Mirror/issues/3362
identity.isClient = true; identity.isClient = true;
identity.OnStartClient(); identity.isLocalPlayer = localPlayer == identity;
// .connectionToServer is only available for local players.
// set it here, before invoking any callbacks.
// this way it's available in _all_ callbacks.
if (identity.isLocalPlayer)
identity.connectionToServer = connection;
} }
internal static void CheckForLocalPlayer(NetworkIdentity identity) // invoke NetworkIdentity callbacks on the client.
// needs to be separate from configuring flags.
// cleaner, and some places need to set flags first.
static void InvokeIdentityCallbacks(NetworkIdentity identity)
{ {
if (identity == localPlayer) // invoke OnStartAuthority
{ identity.NotifyAuthority();
// Set isLocalPlayer to true on this NetworkIdentity and trigger
// OnStartLocalPlayer in all scripts on the same GO
identity.connectionToServer = connection;
// isLocalPlayer is already set by CheckForStartPlayer. // invoke OnStartClient
// however, let's simply move it out of OnStartLocalPlayer for now. identity.OnStartClient();
identity.isLocalPlayer = true;
// invoke OnStartLocalPlayer
if (identity.isLocalPlayer)
identity.OnStartLocalPlayer(); identity.OnStartLocalPlayer();
// Debug.Log($"NetworkClient.OnOwnerMessage player:{identity.name}"); }
}
// configure flags & invoke callbacks
static void BootstrapIdentity(NetworkIdentity identity)
{
InitializeIdentityFlags(identity);
InvokeIdentityCallbacks(identity);
} }
// broadcast /////////////////////////////////////////////////////////// // broadcast ///////////////////////////////////////////////////////////
@ -1473,13 +1501,10 @@ internal static void NetworkLateUpdate()
// also important for syncInterval=0 components like // also important for syncInterval=0 components like
// NetworkTransform, so they can sync on same interval as time // NetworkTransform, so they can sync on same interval as time
// snapshots _but_ not every single tick. // snapshots _but_ not every single tick.
//
// Unity 2019 doesn't have Time.timeAsDouble yet
if (!Application.isPlaying || if (!Application.isPlaying ||
#if !UNITY_2020_3_OR_NEWER
// Unity 2019 doesn't have Time.timeAsDouble yet
AccurateInterval.Elapsed(NetworkTime.localTime, sendInterval, ref lastSendTime)) AccurateInterval.Elapsed(NetworkTime.localTime, sendInterval, ref lastSendTime))
#else
AccurateInterval.Elapsed(Time.timeAsDouble, sendInterval, ref lastSendTime))
#endif
{ {
Broadcast(); Broadcast();
} }

View File

@ -523,7 +523,6 @@ void FinishStartHost()
SetupClient(); SetupClient();
networkAddress = "localhost"; networkAddress = "localhost";
HostMode.ActivateHostScene();
RegisterClientMessages(); RegisterClientMessages();
// call OnConencted needs to be called AFTER RegisterClientMessages // call OnConencted needs to be called AFTER RegisterClientMessages

View File

@ -821,7 +821,7 @@ public static void UnregisterHandler<T>()
internal static bool GetNetworkIdentity(GameObject go, out NetworkIdentity identity) internal static bool GetNetworkIdentity(GameObject go, out NetworkIdentity identity)
{ {
if (!go.TryGetComponent<NetworkIdentity>(out identity)) if (!go.TryGetComponent(out identity))
{ {
Debug.LogError($"GameObject {go.name} doesn't have NetworkIdentity."); Debug.LogError($"GameObject {go.name} doesn't have NetworkIdentity.");
return false; return false;
@ -898,7 +898,7 @@ public static bool AddPlayerForConnection(NetworkConnectionToClient conn, GameOb
// on this playerControllerId for this connection, this will fail. // on this playerControllerId for this connection, this will fail.
public static bool AddPlayerForConnection(NetworkConnectionToClient conn, GameObject player) public static bool AddPlayerForConnection(NetworkConnectionToClient conn, GameObject player)
{ {
if (!player.TryGetComponent<NetworkIdentity>(out NetworkIdentity identity)) if (!player.TryGetComponent(out NetworkIdentity identity))
{ {
Debug.LogWarning($"AddPlayer: playerGameObject has no NetworkIdentity. Please add a NetworkIdentity to {player}"); Debug.LogWarning($"AddPlayer: playerGameObject has no NetworkIdentity. Please add a NetworkIdentity to {player}");
return false; return false;
@ -939,7 +939,7 @@ public static bool AddPlayerForConnection(NetworkConnectionToClient conn, GameOb
// safely be used while changing scenes. // safely be used while changing scenes.
public static bool ReplacePlayerForConnection(NetworkConnectionToClient conn, GameObject player, bool keepAuthority = false) public static bool ReplacePlayerForConnection(NetworkConnectionToClient conn, GameObject player, bool keepAuthority = false)
{ {
if (!player.TryGetComponent<NetworkIdentity>(out NetworkIdentity identity)) if (!player.TryGetComponent(out NetworkIdentity identity))
{ {
Debug.LogError($"ReplacePlayer: playerGameObject has no NetworkIdentity. Please add a NetworkIdentity to {player}"); Debug.LogError($"ReplacePlayer: playerGameObject has no NetworkIdentity. Please add a NetworkIdentity to {player}");
return false; return false;
@ -1288,7 +1288,7 @@ public static bool SpawnObjects()
// This is the same as calling NetworkIdentity.AssignClientAuthority on the spawned object. // This is the same as calling NetworkIdentity.AssignClientAuthority on the spawned object.
public static void Spawn(GameObject obj, GameObject ownerPlayer) public static void Spawn(GameObject obj, GameObject ownerPlayer)
{ {
if (!ownerPlayer.TryGetComponent<NetworkIdentity>(out NetworkIdentity identity)) if (!ownerPlayer.TryGetComponent(out NetworkIdentity identity))
{ {
Debug.LogError("Player object has no NetworkIdentity"); Debug.LogError("Player object has no NetworkIdentity");
return; return;
@ -1351,7 +1351,7 @@ static void SpawnObject(GameObject obj, NetworkConnection ownerConnection)
return; return;
} }
if (!obj.TryGetComponent<NetworkIdentity>(out NetworkIdentity identity)) if (!obj.TryGetComponent(out NetworkIdentity identity))
{ {
Debug.LogError($"SpawnObject {obj} has no NetworkIdentity. Please add a NetworkIdentity to {obj}", obj); Debug.LogError($"SpawnObject {obj} has no NetworkIdentity. Please add a NetworkIdentity to {obj}", obj);
return; return;
@ -1385,6 +1385,8 @@ static void SpawnObject(GameObject obj, NetworkConnection ownerConnection)
if (!identity.isServer && identity.netId == 0) if (!identity.isServer && identity.netId == 0)
{ {
// configure NetworkIdentity // configure NetworkIdentity
// this may be called in host mode, so we need to initialize
// isLocalPlayer/isClient flags too.
identity.isLocalPlayer = NetworkClient.localPlayer == identity; identity.isLocalPlayer = NetworkClient.localPlayer == identity;
identity.isClient = NetworkClient.active; identity.isClient = NetworkClient.active;
identity.isServer = true; identity.isServer = true;

View File

@ -239,7 +239,7 @@ public static void WriteTransform(this NetworkWriter writer, Transform value)
writer.WriteUInt(0); writer.WriteUInt(0);
return; return;
} }
if (value.TryGetComponent<NetworkIdentity>(out NetworkIdentity identity)) if (value.TryGetComponent(out NetworkIdentity identity))
{ {
writer.WriteUInt(identity.netId); writer.WriteUInt(identity.netId);
} }
@ -259,7 +259,7 @@ public static void WriteGameObject(this NetworkWriter writer, GameObject value)
} }
// warn if the GameObject doesn't have a NetworkIdentity, // warn if the GameObject doesn't have a NetworkIdentity,
if (!value.TryGetComponent<NetworkIdentity>(out NetworkIdentity identity)) if (!value.TryGetComponent(out NetworkIdentity identity))
Debug.LogWarning($"NetworkWriter {value} has no NetworkIdentity"); Debug.LogWarning($"NetworkWriter {value} has no NetworkIdentity");
// serialize the correct amount of data in any case to make sure // serialize the correct amount of data in any case to make sure

View File

@ -1,5 +1,4 @@
// API consistent with Microsoft's ObjectPool<T>. // API consistent with Microsoft's ObjectPool<T>.
using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace Mirror namespace Mirror

View File

@ -72,7 +72,7 @@ IEnumerator LoadAdditive(string sceneName)
isInTransition = true; isInTransition = true;
// This will return immediately if already faded in // This will return immediately if already faded in
// e.g. by UnloadAdditive above or by default startup state // e.g. by UnloadAdditive or by default startup state
yield return fadeInOut.FadeIn(); yield return fadeInOut.FadeIn();
// host client is on server...don't load the additive scene again // host client is on server...don't load the additive scene again
@ -91,6 +91,7 @@ IEnumerator LoadAdditive(string sceneName)
OnClientSceneChanged(); OnClientSceneChanged();
// Reveal the new scene content.
yield return fadeInOut.FadeOut(); yield return fadeInOut.FadeOut();
} }
@ -99,9 +100,10 @@ IEnumerator UnloadAdditive(string sceneName)
isInTransition = true; isInTransition = true;
// This will return immediately if already faded in // This will return immediately if already faded in
// e.g. by LoadAdditive above or by default startup state // e.g. by LoadAdditive above or by default startup state.
yield return fadeInOut.FadeIn(); yield return fadeInOut.FadeIn();
// host client is on server...don't unload the additive scene here.
if (mode == NetworkManagerMode.ClientOnly) if (mode == NetworkManagerMode.ClientOnly)
{ {
yield return SceneManager.UnloadSceneAsync(sceneName); yield return SceneManager.UnloadSceneAsync(sceneName);
@ -115,8 +117,8 @@ IEnumerator UnloadAdditive(string sceneName)
OnClientSceneChanged(); OnClientSceneChanged();
// There is no call to FadeOut here on purpose. // There is no call to FadeOut here on purpose.
// Expectation is that a LoadAdditive will follow // Expectation is that a LoadAdditive or full scene change
// that will call FadeOut after that scene loads. // will follow that will call FadeOut after that scene loads.
} }
/// <summary> /// <summary>

View File

@ -46,7 +46,7 @@ void OnTriggerEnter(Collider other)
//Debug.Log($"{System.DateTime.Now:HH:mm:ss:fff} Portal::OnTriggerEnter {gameObject.name} in {gameObject.scene.name}"); //Debug.Log($"{System.DateTime.Now:HH:mm:ss:fff} Portal::OnTriggerEnter {gameObject.name} in {gameObject.scene.name}");
// applies to host client on server and remote clients // applies to host client on server and remote clients
if (other.TryGetComponent<PlayerController>(out PlayerController playerController)) if (other.TryGetComponent(out PlayerController playerController))
playerController.enabled = false; playerController.enabled = false;
if (isServer) if (isServer)
@ -56,7 +56,7 @@ void OnTriggerEnter(Collider other)
[ServerCallback] [ServerCallback]
IEnumerator SendPlayerToNewScene(GameObject player) IEnumerator SendPlayerToNewScene(GameObject player)
{ {
if (player.TryGetComponent<NetworkIdentity>(out NetworkIdentity identity)) if (player.TryGetComponent(out NetworkIdentity identity))
{ {
NetworkConnectionToClient conn = identity.connectionToClient; NetworkConnectionToClient conn = identity.connectionToClient;
if (conn == null) yield break; if (conn == null) yield break;
@ -83,7 +83,7 @@ IEnumerator SendPlayerToNewScene(GameObject player)
NetworkServer.AddPlayerForConnection(conn, player); NetworkServer.AddPlayerForConnection(conn, player);
// host client would have been disabled by OnTriggerEnter above // host client would have been disabled by OnTriggerEnter above
if (NetworkClient.localPlayer != null && NetworkClient.localPlayer.TryGetComponent<PlayerController>(out PlayerController playerController)) if (NetworkClient.localPlayer != null && NetworkClient.localPlayer.TryGetComponent(out PlayerController playerController))
playerController.enabled = true; playerController.enabled = true;
} }
} }

View File

@ -28,6 +28,9 @@ void Update()
// (SyncVar hook would only update on clients, not on server) // (SyncVar hook would only update on clients, not on server)
healthBar.text = new string('-', health); healthBar.text = new string('-', health);
// take input from focused window only
if(!Application.isFocused) return;
// movement for local player // movement for local player
if (isLocalPlayer) if (isLocalPlayer)
{ {

View File

@ -21,7 +21,7 @@ public void TestIntReaderNotNull()
public void TestAccessingCustomWriterAndReader() public void TestAccessingCustomWriterAndReader()
{ {
NetworkWriter writer = new NetworkWriter(); NetworkWriter writer = new NetworkWriter();
writer.Write<int>(3); writer.Write(3);
NetworkReader reader = new NetworkReader(writer.ToArray()); NetworkReader reader = new NetworkReader(writer.ToArray());
int copy = reader.Read<int>(); int copy = reader.Read<int>();

View File

@ -839,28 +839,6 @@ public void SendCommand_RequiresAuthority()
Assert.That(comp.called, Is.EqualTo(0)); Assert.That(comp.called, Is.EqualTo(0));
} }
[Test]
public void ActivateHostSceneCallsOnStartClient()
{
// listen & connect
NetworkServer.Listen(1);
ConnectClientBlockingAuthenticatedAndReady(out _);
// spawn identity with a networkbehaviour.
// (needs to be in .spawned for ActivateHostScene)
CreateNetworkedAndSpawn(
out _, out NetworkIdentity serverIdentity, out OnStartClientTestNetworkBehaviour serverComp,
out _, out _, out _);
// ActivateHostScene calls OnStartClient for spawned objects where
// isClient is still false. set it to false first.
serverIdentity.isClient = false;
HostMode.ActivateHostScene();
// was OnStartClient called for all .spawned networkidentities?
Assert.That(serverComp.called, Is.EqualTo(1));
}
[Test] [Test]
public void SendToAll() public void SendToAll()
{ {

View File

@ -1,3 +1,11 @@
V1.29 [2023-01-28]
- fix: KcpServer.CreateServerSocket now handles NotSupportedException when setting DualMode
https://github.com/MirrorNetworking/Mirror/issues/3358
V1.28 [2023-01-28]
- fix: KcpClient.Connect now resolves hostname before creating peer
https://github.com/MirrorNetworking/Mirror/issues/3361
V1.27 [2023-01-08] V1.27 [2023-01-08]
- KcpClient.Connect: invoke own events directly instead of going through peer, - KcpClient.Connect: invoke own events directly instead of going through peer,
which calls our own events anyway which calls our own events anyway

View File

@ -60,6 +60,16 @@ public void Connect(string address, ushort port, KcpConfig config)
return; return;
} }
// resolve host name before creating peer.
// fixes: https://github.com/MirrorNetworking/Mirror/issues/3361
if (!Common.ResolveHostname(address, out IPAddress[] addresses))
{
// pass error to user callback. no need to log it manually.
OnError(ErrorCode.DnsResolve, $"Failed to resolve host: {address}");
OnDisconnected();
return;
}
// create fresh peer for each new session // create fresh peer for each new session
peer = new KcpPeer(RawSend, OnAuthenticatedWrap, OnData, OnDisconnectedWrap, OnError, config); peer = new KcpPeer(RawSend, OnAuthenticatedWrap, OnData, OnDisconnectedWrap, OnError, config);
@ -83,15 +93,6 @@ void OnDisconnectedWrap()
Log.Info($"KcpClient: connect to {address}:{port}"); Log.Info($"KcpClient: connect to {address}:{port}");
// try resolve host name
if (!Common.ResolveHostname(address, out IPAddress[] addresses))
{
// pass error to user callback. no need to log it manually.
OnError(ErrorCode.DnsResolve, $"Failed to resolve host: {address}");
OnDisconnected();
return;
}
// create socket // create socket
remoteEndPoint = new IPEndPoint(addresses[0], port); remoteEndPoint = new IPEndPoint(addresses[0], port);
socket = new Socket(remoteEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp); socket = new Socket(remoteEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);

View File

@ -67,7 +67,18 @@ static Socket CreateServerSocket(bool DualMode, ushort port)
{ {
// IPv6 socket with DualMode @ "::" : port // IPv6 socket with DualMode @ "::" : port
Socket socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp); Socket socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);
socket.DualMode = true; // settings DualMode may throw:
// https://learn.microsoft.com/en-us/dotnet/api/System.Net.Sockets.Socket.DualMode?view=net-7.0
// attempt it, otherwise log but continue
// fixes: https://github.com/MirrorNetworking/Mirror/issues/3358
try
{
socket.DualMode = true;
}
catch (NotSupportedException e)
{
Log.Warning($"Failed to set Dual Mode, continuing with IPv6 without Dual Mode. Error: {e}");
}
socket.Bind(new IPEndPoint(IPAddress.IPv6Any, port)); socket.Bind(new IPEndPoint(IPAddress.IPv6Any, port));
return socket; return socket;
} }

View File

@ -32,9 +32,8 @@ public class #SCRIPTNAME# : InterestManagement
/// </summary> /// </summary>
/// <param name="identity">Object to be observed (or not) by clients</param> /// <param name="identity">Object to be observed (or not) by clients</param>
/// <param name="newObservers">cached hashset to put the result into</param> /// <param name="newObservers">cached hashset to put the result into</param>
/// <param name="initialize">true if being rebuilt for the first time</param>
[ServerCallback] [ServerCallback]
public override void OnRebuildObservers(NetworkIdentity identity, HashSet<NetworkConnectionToClient> newObservers, bool initialize) public override void OnRebuildObservers(NetworkIdentity identity, HashSet<NetworkConnectionToClient> newObservers)
{ {
// Default behaviour of making the identity object visible to all clients. // Default behaviour of making the identity object visible to all clients.
// Replace this code with your own logic as appropriate. // Replace this code with your own logic as appropriate.

View File

@ -2,8 +2,8 @@
"dependencies": { "dependencies": {
"com.unity.2d.sprite": "1.0.0", "com.unity.2d.sprite": "1.0.0",
"com.unity.2d.tilemap": "1.0.0", "com.unity.2d.tilemap": "1.0.0",
"com.unity.ide.rider": "3.0.16", "com.unity.ide.rider": "3.0.18",
"com.unity.ide.visualstudio": "2.0.16", "com.unity.ide.visualstudio": "2.0.17",
"com.unity.ide.vscode": "1.2.5", "com.unity.ide.vscode": "1.2.5",
"com.unity.test-framework": "1.1.31", "com.unity.test-framework": "1.1.31",
"com.unity.testtools.codecoverage": "1.2.2", "com.unity.testtools.codecoverage": "1.2.2",

View File

@ -20,7 +20,7 @@
"url": "https://packages.unity.com" "url": "https://packages.unity.com"
}, },
"com.unity.ide.rider": { "com.unity.ide.rider": {
"version": "3.0.16", "version": "3.0.18",
"depth": 0, "depth": 0,
"source": "registry", "source": "registry",
"dependencies": { "dependencies": {
@ -29,7 +29,7 @@
"url": "https://packages.unity.com" "url": "https://packages.unity.com"
}, },
"com.unity.ide.visualstudio": { "com.unity.ide.visualstudio": {
"version": "2.0.16", "version": "2.0.17",
"depth": 0, "depth": 0,
"source": "registry", "source": "registry",
"dependencies": { "dependencies": {

View File

@ -1,2 +1,2 @@
m_EditorVersion: 2021.3.15f1 m_EditorVersion: 2021.3.17f1
m_EditorVersionWithRevision: 2021.3.15f1 (e8e88683f834) m_EditorVersionWithRevision: 2021.3.17f1 (3e8111cac19d)