2018-06-07 13:41:08 +00:00
#if ENABLE_UNET
using System ;
using System.Collections.Generic ;
2018-06-11 10:38:44 +00:00
using System.Linq ;
2018-06-07 13:41:08 +00:00
using UnityEngine.Networking.NetworkSystem ;
using UnityEngine.Networking.Types ;
namespace UnityEngine.Networking
{
public sealed class NetworkServer
{
static bool s_Active ;
2018-06-22 18:34:35 +00:00
static bool s_DontListen ;
2018-06-22 13:18:23 +00:00
static bool s_LocalClientActive ;
2018-06-22 18:34:35 +00:00
static ULocalConnectionToClient s_LocalConnection ;
2018-06-07 13:41:08 +00:00
2018-06-22 18:34:35 +00:00
static NetworkScene s_NetworkScene = new NetworkScene ( ) ;
static HashSet < int > s_ExternalConnections = new HashSet < int > ( ) ;
2018-06-07 13:41:08 +00:00
2018-07-19 18:48:37 +00:00
static Dictionary < short , NetworkMessageDelegate > s_MessageHandlers = new Dictionary < short , NetworkMessageDelegate > ( ) ;
2018-06-22 18:34:35 +00:00
static List < NetworkConnection > s_Connections = new List < NetworkConnection > ( ) ;
2018-06-22 13:18:23 +00:00
2018-06-22 18:34:35 +00:00
static int s_ServerHostId = - 1 ;
static int s_ServerPort = - 1 ;
static HostTopology s_HostTopology ;
static byte [ ] s_MsgBuffer = new byte [ NetworkMessage . MaxMessageSize ] ;
static bool s_UseWebSockets ;
static bool s_Initialized = false ;
2018-06-22 13:18:23 +00:00
2018-06-07 13:41:08 +00:00
// this is cached here for easy access when checking the size of state update packets in NetworkIdentity
static internal ushort maxPacketSize ;
2018-06-22 10:14:41 +00:00
// original HLAPI has .localConnections list with only m_LocalConnection in it
// (for downwards compatibility because they removed the real localConnections list a while ago)
// => removed it for easier code. use .localConection now!
2018-06-22 18:34:35 +00:00
public static NetworkConnection localConnection { get { return ( NetworkConnection ) s_LocalConnection ; } }
2018-06-07 13:41:08 +00:00
2018-06-22 18:34:35 +00:00
public static int listenPort { get { return s_ServerPort ; } }
public static int serverHostId { get { return s_ServerHostId ; } }
2018-06-07 13:41:08 +00:00
2018-06-22 18:34:35 +00:00
public static List < NetworkConnection > connections { get { return s_Connections ; } }
2018-07-19 18:48:37 +00:00
public static Dictionary < short , NetworkMessageDelegate > handlers { get { return s_MessageHandlers ; } }
2018-06-22 18:34:35 +00:00
public static HostTopology hostTopology { get { return s_HostTopology ; } }
2018-06-07 13:41:08 +00:00
2018-06-22 13:18:23 +00:00
public static Dictionary < NetworkInstanceId , NetworkIdentity > objects { get { return s_NetworkScene . localObjects ; } }
2018-06-22 18:34:35 +00:00
public static bool dontListen { get { return s_DontListen ; } set { s_DontListen = value ; } }
public static bool useWebSockets { get { return s_UseWebSockets ; } set { s_UseWebSockets = value ; } }
2018-06-07 13:41:08 +00:00
public static bool active { get { return s_Active ; } }
2018-06-22 13:18:23 +00:00
public static bool localClientActive { get { return s_LocalClientActive ; } }
2018-06-22 18:34:35 +00:00
public static int numChannels { get { return s_HostTopology . DefaultConfig . ChannelCount ; } }
2018-06-07 13:41:08 +00:00
2018-06-22 13:18:23 +00:00
static Type s_NetworkConnectionClass = typeof ( NetworkConnection ) ;
public static Type networkConnectionClass { get { return s_NetworkConnectionClass ; } }
2018-06-07 13:41:08 +00:00
static public void SetNetworkConnectionClass < T > ( ) where T : NetworkConnection
{
2018-06-22 13:18:23 +00:00
s_NetworkConnectionClass = typeof ( T ) ;
2018-06-07 13:41:08 +00:00
}
static public bool Configure ( ConnectionConfig config , int maxConnections )
{
2018-06-22 13:18:23 +00:00
HostTopology top = new HostTopology ( config , maxConnections ) ;
return Configure ( top ) ;
2018-06-07 13:41:08 +00:00
}
static public bool Configure ( HostTopology topology )
{
2018-06-22 18:34:35 +00:00
s_HostTopology = topology ;
2018-06-22 13:18:23 +00:00
return true ;
2018-06-07 13:41:08 +00:00
}
public static void Reset ( )
{
#if UNITY_EDITOR
UnityEditor . NetworkDetailStats . ResetAll ( ) ;
#endif
NetworkTransport . Shutdown ( ) ;
NetworkTransport . Init ( ) ;
s_Active = false ;
}
public static void Shutdown ( )
{
2018-06-22 18:34:35 +00:00
if ( s_Initialized )
2018-06-07 13:41:08 +00:00
{
2018-06-22 18:34:35 +00:00
InternalDisconnectAll ( ) ;
2018-06-07 13:41:08 +00:00
2018-06-22 18:34:35 +00:00
if ( s_DontListen )
2018-06-07 13:41:08 +00:00
{
// was never started, so dont stop
}
else
{
2018-06-22 18:34:35 +00:00
NetworkTransport . RemoveHost ( s_ServerHostId ) ;
s_ServerHostId = - 1 ;
2018-06-07 13:41:08 +00:00
}
2018-06-22 18:34:35 +00:00
s_Initialized = false ;
2018-06-07 13:41:08 +00:00
}
2018-06-22 18:34:35 +00:00
s_DontListen = false ;
2018-06-07 13:41:08 +00:00
s_Active = false ;
}
2018-06-22 18:34:35 +00:00
public static void Initialize ( )
2018-06-22 13:18:23 +00:00
{
2018-06-22 18:34:35 +00:00
if ( s_Initialized )
2018-06-22 13:18:23 +00:00
return ;
2018-06-22 18:34:35 +00:00
s_Initialized = true ;
2018-06-22 13:18:23 +00:00
NetworkTransport . Init ( ) ;
2018-06-22 18:34:35 +00:00
if ( LogFilter . logDev ) { Debug . Log ( "NetworkServer Created version " + Version . Current ) ; }
2018-06-22 13:18:23 +00:00
2018-06-22 18:34:35 +00:00
s_MsgBuffer = new byte [ NetworkMessage . MaxMessageSize ] ;
2018-06-22 13:18:23 +00:00
2018-06-22 18:34:35 +00:00
if ( s_HostTopology = = null )
2018-06-22 13:18:23 +00:00
{
var config = new ConnectionConfig ( ) ;
config . AddChannel ( QosType . ReliableSequenced ) ;
config . AddChannel ( QosType . Unreliable ) ;
2018-06-22 18:34:35 +00:00
s_HostTopology = new HostTopology ( config , 8 ) ;
2018-06-22 13:18:23 +00:00
}
if ( LogFilter . logDebug ) { Debug . Log ( "NetworkServer initialize." ) ; }
}
2018-06-22 18:34:35 +00:00
static internal void RegisterMessageHandlers ( )
2018-06-07 13:41:08 +00:00
{
2018-07-19 19:03:00 +00:00
RegisterHandler ( ( short ) MsgType . Ready , OnClientReadyMessage ) ;
RegisterHandler ( ( short ) MsgType . Command , OnCommandMessage ) ;
RegisterHandler ( ( short ) MsgType . LocalPlayerTransform , NetworkTransform . HandleTransform ) ;
RegisterHandler ( ( short ) MsgType . LocalChildTransform , NetworkTransformChild . HandleChildTransform ) ;
RegisterHandler ( ( short ) MsgType . RemovePlayer , OnRemovePlayerMessage ) ;
RegisterHandler ( ( short ) MsgType . Animation , NetworkAnimator . OnAnimationServerMessage ) ;
RegisterHandler ( ( short ) MsgType . AnimationParameters , NetworkAnimator . OnAnimationParametersServerMessage ) ;
RegisterHandler ( ( short ) MsgType . AnimationTrigger , NetworkAnimator . OnAnimationTriggerServerMessage ) ;
2018-06-07 13:41:08 +00:00
// also setup max packet size.
maxPacketSize = hostTopology . DefaultConfig . PacketSize ;
}
static public bool Listen ( int serverPort )
{
2018-06-22 18:34:35 +00:00
return InternalListen ( null , serverPort ) ;
2018-06-07 13:41:08 +00:00
}
static public bool Listen ( string ipAddress , int serverPort )
{
2018-06-22 18:34:35 +00:00
return InternalListen ( ipAddress , serverPort ) ;
2018-06-07 13:41:08 +00:00
}
2018-06-22 18:34:35 +00:00
static internal bool InternalListen ( string ipAddress , int serverPort )
2018-06-07 13:41:08 +00:00
{
2018-06-22 13:18:23 +00:00
Initialize ( ) ;
// only start server if we want to listen. otherwise this mode uses external connections instead
2018-07-20 10:29:51 +00:00
if ( ! s_DontListen )
2018-06-07 13:41:08 +00:00
{
2018-06-22 13:18:23 +00:00
Initialize ( ) ;
2018-06-22 18:34:35 +00:00
s_ServerPort = serverPort ;
2018-06-22 13:18:23 +00:00
2018-06-22 18:34:35 +00:00
if ( s_UseWebSockets )
2018-06-22 13:18:23 +00:00
{
2018-06-22 18:34:35 +00:00
s_ServerHostId = NetworkTransport . AddWebsocketHost ( s_HostTopology , serverPort , ipAddress ) ;
2018-06-22 13:18:23 +00:00
}
else
{
2018-06-22 18:34:35 +00:00
s_ServerHostId = NetworkTransport . AddHost ( s_HostTopology , serverPort , ipAddress ) ;
2018-06-22 13:18:23 +00:00
}
2018-06-22 18:34:35 +00:00
if ( s_ServerHostId = = - 1 )
2018-06-22 13:18:23 +00:00
{
2018-06-07 13:41:08 +00:00
return false ;
2018-06-22 13:18:23 +00:00
}
2018-06-22 18:34:35 +00:00
if ( LogFilter . logDebug ) { Debug . Log ( "Server listen: " + ipAddress + ":" + s_ServerPort ) ; }
2018-06-07 13:41:08 +00:00
}
maxPacketSize = hostTopology . DefaultConfig . PacketSize ;
s_Active = true ;
RegisterMessageHandlers ( ) ;
return true ;
}
2018-06-22 18:34:35 +00:00
public static bool SetConnectionAtIndex ( NetworkConnection conn )
2018-06-22 13:18:23 +00:00
{
2018-06-22 18:34:35 +00:00
while ( s_Connections . Count < = conn . connectionId )
2018-06-22 13:18:23 +00:00
{
2018-06-22 18:34:35 +00:00
s_Connections . Add ( null ) ;
2018-06-22 13:18:23 +00:00
}
2018-06-22 18:34:35 +00:00
if ( s_Connections [ conn . connectionId ] ! = null )
2018-06-22 13:18:23 +00:00
{
// already a connection at this index
return false ;
}
2018-06-22 18:34:35 +00:00
s_Connections [ conn . connectionId ] = conn ;
conn . SetHandlers ( s_MessageHandlers ) ;
2018-06-22 13:18:23 +00:00
return true ;
}
2018-06-22 18:34:35 +00:00
public static bool RemoveConnectionAtIndex ( int connectionId )
2018-06-22 13:18:23 +00:00
{
2018-06-22 18:34:35 +00:00
if ( connectionId < 0 | | connectionId > = s_Connections . Count )
2018-06-22 13:18:23 +00:00
return false ;
2018-06-22 18:34:35 +00:00
s_Connections . RemoveAt ( connectionId ) ;
2018-06-22 13:18:23 +00:00
return true ;
}
2018-06-07 13:41:08 +00:00
// called by LocalClient to add itself. dont call directly.
2018-06-22 18:34:35 +00:00
static internal int AddLocalClient ( LocalClient localClient )
2018-06-07 13:41:08 +00:00
{
2018-06-22 18:34:35 +00:00
if ( s_LocalConnection ! = null )
2018-06-07 13:41:08 +00:00
{
Debug . LogError ( "Local Connection already exists" ) ;
return - 1 ;
}
2018-06-22 18:34:35 +00:00
s_LocalConnection = new ULocalConnectionToClient ( localClient ) ;
s_LocalConnection . connectionId = 0 ;
SetConnectionAtIndex ( s_LocalConnection ) ;
2018-06-07 13:41:08 +00:00
2018-07-19 19:03:00 +00:00
s_LocalConnection . InvokeHandlerNoData ( ( short ) MsgType . Connect ) ;
2018-06-07 13:41:08 +00:00
return 0 ;
}
2018-06-22 18:34:35 +00:00
static internal void RemoveLocalClient ( NetworkConnection localClientConnection )
2018-06-07 13:41:08 +00:00
{
2018-06-22 18:34:35 +00:00
if ( s_LocalConnection ! = null )
2018-06-07 13:41:08 +00:00
{
2018-06-22 18:34:35 +00:00
s_LocalConnection . Disconnect ( ) ;
s_LocalConnection . Dispose ( ) ;
s_LocalConnection = null ;
2018-06-07 13:41:08 +00:00
}
2018-06-22 13:18:23 +00:00
s_LocalClientActive = false ;
RemoveConnectionAtIndex ( 0 ) ;
2018-06-07 13:41:08 +00:00
}
2018-06-22 18:34:35 +00:00
static internal void SetLocalObjectOnServer ( NetworkInstanceId netId , GameObject obj )
2018-06-07 13:41:08 +00:00
{
if ( LogFilter . logDev ) { Debug . Log ( "SetLocalObjectOnServer " + netId + " " + obj ) ; }
2018-06-22 13:18:23 +00:00
s_NetworkScene . SetLocalObject ( netId , obj , false , true ) ;
2018-06-07 13:41:08 +00:00
}
2018-06-22 18:34:35 +00:00
static internal void ActivateLocalClientScene ( )
2018-06-07 13:41:08 +00:00
{
2018-06-22 13:18:23 +00:00
if ( s_LocalClientActive )
2018-06-07 13:41:08 +00:00
return ;
// ClientScene for a local connection is becoming active. any spawned objects need to be started as client objects
2018-06-22 13:18:23 +00:00
s_LocalClientActive = true ;
2018-06-07 13:41:08 +00:00
foreach ( var uv in objects . Values )
{
if ( ! uv . isClient )
{
if ( LogFilter . logDev ) { Debug . Log ( "ActivateClientScene " + uv . netId + " " + uv . gameObject ) ; }
ClientScene . SetLocalObject ( uv . netId , uv . gameObject ) ;
uv . OnStartClient ( ) ;
}
}
}
2018-06-22 13:18:23 +00:00
// this is like SendToReady - but it doesn't check the ready flag on the connection.
// this is used for ObjectDestroy messages.
2018-06-07 13:41:08 +00:00
static bool SendToObservers ( GameObject contextObj , short msgType , MessageBase msg )
{
if ( LogFilter . logDev ) { Debug . Log ( "Server.SendToObservers id:" + msgType ) ; }
var uv = contextObj . GetComponent < NetworkIdentity > ( ) ;
2018-06-11 10:38:44 +00:00
if ( uv ! = null & & uv . observers ! = null )
2018-06-07 13:41:08 +00:00
{
2018-06-11 10:38:44 +00:00
bool result = true ;
for ( int i = 0 ; i < uv . observers . Count ; + + i )
{
var conn = uv . observers [ i ] ;
result & = conn . Send ( msgType , msg ) ;
}
return result ;
2018-06-07 13:41:08 +00:00
}
2018-06-11 10:38:44 +00:00
return false ;
2018-06-07 13:41:08 +00:00
}
2018-07-19 16:06:25 +00:00
// End users should not send random bytes
// because the other side might interpret them as messages
2018-07-20 10:29:51 +00:00
static internal void SendBytesToReady ( GameObject contextObj , byte [ ] buffer , int channelId )
2018-06-07 13:41:08 +00:00
{
if ( contextObj = = null )
{
// no context.. send to all ready connections
bool success = true ;
for ( int i = 0 ; i < connections . Count ; i + + )
{
NetworkConnection conn = connections [ i ] ;
if ( conn ! = null & & conn . isReady )
{
2018-07-20 10:29:51 +00:00
if ( ! conn . SendBytes ( buffer , channelId ) )
2018-06-07 13:41:08 +00:00
{
success = false ;
}
}
}
if ( ! success )
{
if ( LogFilter . logWarn ) { Debug . LogWarning ( "SendBytesToReady failed" ) ; }
}
return ;
}
var uv = contextObj . GetComponent < NetworkIdentity > ( ) ;
try
{
bool success = true ;
2018-06-11 10:38:44 +00:00
for ( int i = 0 ; i < uv . observers . Count ; + + i )
2018-06-07 13:41:08 +00:00
{
var conn = uv . observers [ i ] ;
2018-06-11 10:38:44 +00:00
if ( conn . isReady )
2018-06-07 13:41:08 +00:00
{
2018-07-20 10:29:51 +00:00
if ( ! conn . SendBytes ( buffer , channelId ) )
2018-06-11 10:38:44 +00:00
{
success = false ;
}
2018-06-07 13:41:08 +00:00
}
}
if ( ! success )
{
if ( LogFilter . logWarn ) { Debug . LogWarning ( "SendBytesToReady failed for " + contextObj ) ; }
}
}
catch ( NullReferenceException )
{
// observers may be null if object has not been spawned
if ( LogFilter . logWarn ) { Debug . LogWarning ( "SendBytesToReady object " + contextObj + " has not been spawned" ) ; }
}
}
static public bool SendByChannelToAll ( short msgType , MessageBase msg , int channelId )
{
if ( LogFilter . logDev ) { Debug . Log ( "Server.SendByChannelToAll id:" + msgType ) ; }
bool result = true ;
for ( int i = 0 ; i < connections . Count ; i + + )
{
2018-07-16 18:07:26 +00:00
NetworkConnection conn = connections [ i ] ;
2018-06-07 13:41:08 +00:00
if ( conn ! = null )
result & = conn . SendByChannel ( msgType , msg , channelId ) ;
}
return result ;
}
2018-07-16 18:07:26 +00:00
static public bool SendToAll ( short msgType , MessageBase msg ) { return SendByChannelToAll ( msgType , msg , Channels . DefaultReliable ) ; }
static public bool SendUnreliableToAll ( short msgType , MessageBase msg ) { return SendByChannelToAll ( msgType , msg , Channels . DefaultUnreliable ) ; }
2018-06-07 13:41:08 +00:00
static public bool SendByChannelToReady ( GameObject contextObj , short msgType , MessageBase msg , int channelId )
{
if ( LogFilter . logDev ) { Debug . Log ( "Server.SendByChannelToReady msgType:" + msgType ) ; }
if ( contextObj = = null )
{
// no context.. send to all ready connections
for ( int i = 0 ; i < connections . Count ; i + + )
{
2018-07-16 18:17:20 +00:00
NetworkConnection conn = connections [ i ] ;
2018-06-07 13:41:08 +00:00
if ( conn ! = null & & conn . isReady )
{
conn . SendByChannel ( msgType , msg , channelId ) ;
}
}
return true ;
}
2018-07-16 18:17:20 +00:00
NetworkIdentity uv = contextObj . GetComponent < NetworkIdentity > ( ) ;
if ( uv ! = null & & uv . observers ! = null )
2018-06-07 13:41:08 +00:00
{
2018-07-16 18:17:20 +00:00
bool result = true ;
for ( int i = 0 ; i < uv . observers . Count ; + + i )
2018-06-11 10:38:44 +00:00
{
2018-07-16 18:17:20 +00:00
NetworkConnection conn = uv . observers [ i ] ;
if ( conn . isReady )
{
result & = conn . SendByChannel ( msgType , msg , channelId ) ;
}
2018-06-11 10:38:44 +00:00
}
2018-07-16 18:17:20 +00:00
return result ;
2018-06-07 13:41:08 +00:00
}
2018-07-16 18:17:20 +00:00
return false ;
2018-06-07 13:41:08 +00:00
}
2018-07-16 18:17:20 +00:00
static public bool SendToReady ( GameObject contextObj , short msgType , MessageBase msg ) { return SendByChannelToReady ( contextObj , msgType , msg , Channels . DefaultReliable ) ; }
static public bool SendUnreliableToReady ( GameObject contextObj , short msgType , MessageBase msg ) { return SendByChannelToReady ( contextObj , msgType , msg , Channels . DefaultUnreliable ) ; }
2018-06-07 13:41:08 +00:00
static public void DisconnectAll ( )
{
2018-06-22 18:34:35 +00:00
InternalDisconnectAll ( ) ;
2018-06-07 13:41:08 +00:00
}
2018-06-22 18:34:35 +00:00
public static void DisconnectAllConnections ( )
2018-06-22 13:18:23 +00:00
{
for ( int i = 0 ; i < connections . Count ; i + + )
{
NetworkConnection conn = connections [ i ] ;
if ( conn ! = null )
{
conn . Disconnect ( ) ;
conn . Dispose ( ) ;
}
}
}
2018-06-22 18:34:35 +00:00
static internal void InternalDisconnectAll ( )
2018-06-07 13:41:08 +00:00
{
2018-06-22 13:18:23 +00:00
DisconnectAllConnections ( ) ;
2018-06-07 13:41:08 +00:00
2018-06-22 18:34:35 +00:00
if ( s_LocalConnection ! = null )
2018-06-07 13:41:08 +00:00
{
2018-06-22 18:34:35 +00:00
s_LocalConnection . Disconnect ( ) ;
s_LocalConnection . Dispose ( ) ;
s_LocalConnection = null ;
2018-06-07 13:41:08 +00:00
}
2018-06-22 13:18:23 +00:00
s_Active = false ;
s_LocalClientActive = false ;
2018-06-07 13:41:08 +00:00
}
// The user should never need to pump the update loop manually
2018-06-22 18:34:35 +00:00
static internal void Update ( )
2018-06-07 13:41:08 +00:00
{
2018-06-22 18:34:35 +00:00
InternalUpdate ( ) ;
2018-06-07 13:41:08 +00:00
}
2018-06-22 18:34:35 +00:00
static void UpdateServerObjects ( )
2018-06-07 13:41:08 +00:00
{
2018-06-11 10:19:42 +00:00
// vis2k: original code only removed null entries every 100 frames. this was unnecessarily complicated and
// probably even slower than removing null entries each time (hence less iterations next time).
List < NetworkInstanceId > remove = new List < NetworkInstanceId > ( ) ;
foreach ( var kvp in objects )
2018-06-07 13:41:08 +00:00
{
2018-06-11 10:19:42 +00:00
if ( kvp . Value ! = null & & kvp . Value . gameObject ! = null )
2018-06-07 13:41:08 +00:00
{
2018-06-11 10:19:42 +00:00
kvp . Value . UNetUpdate ( ) ;
2018-06-07 13:41:08 +00:00
}
2018-06-11 10:19:42 +00:00
else
2018-06-07 13:41:08 +00:00
{
2018-07-20 10:29:51 +00:00
remove . Add ( kvp . Key ) ;
2018-06-07 13:41:08 +00:00
}
}
2018-06-11 10:19:42 +00:00
// now remove
foreach ( NetworkInstanceId key in remove )
2018-06-07 13:41:08 +00:00
{
2018-06-11 10:19:42 +00:00
objects . Remove ( key ) ;
2018-06-07 13:41:08 +00:00
}
}
2018-06-22 18:34:35 +00:00
static internal void InternalUpdate ( )
2018-06-07 13:41:08 +00:00
{
2018-06-22 18:34:35 +00:00
if ( s_ServerHostId = = - 1 )
2018-06-22 13:18:23 +00:00
return ;
int connectionId ;
int channelId ;
int receivedSize ;
byte error ;
var networkEvent = NetworkEventType . DataEvent ;
2018-06-07 13:41:08 +00:00
2018-06-22 13:18:23 +00:00
do
{
2018-06-22 18:34:35 +00:00
networkEvent = NetworkTransport . ReceiveFromHost ( s_ServerHostId , out connectionId , out channelId , s_MsgBuffer , ( ushort ) s_MsgBuffer . Length , out receivedSize , out error ) ;
2018-06-22 13:18:23 +00:00
if ( networkEvent ! = NetworkEventType . Nothing )
{
2018-06-22 18:34:35 +00:00
if ( LogFilter . logDev ) { Debug . Log ( "Server event: host=" + s_ServerHostId + " event=" + networkEvent + " error=" + error ) ; }
2018-06-22 13:18:23 +00:00
}
switch ( networkEvent )
{
case NetworkEventType . ConnectEvent :
{
HandleConnect ( connectionId , error ) ;
break ;
}
case NetworkEventType . DataEvent :
{
HandleData ( connectionId , channelId , receivedSize , error ) ;
break ;
}
case NetworkEventType . DisconnectEvent :
{
HandleDisconnect ( connectionId , error ) ;
break ;
}
case NetworkEventType . Nothing :
{
break ;
}
default :
{
if ( LogFilter . logError ) { Debug . LogError ( "Unknown network message type received: " + networkEvent ) ; }
break ;
}
}
}
while ( networkEvent ! = NetworkEventType . Nothing ) ;
2018-06-07 13:41:08 +00:00
UpdateServerObjects ( ) ;
}
2018-06-22 18:34:35 +00:00
static void HandleConnect ( int connectionId , byte error )
2018-06-22 13:18:23 +00:00
{
if ( LogFilter . logDebug ) { Debug . Log ( "Server accepted client:" + connectionId ) ; }
if ( error ! = 0 )
{
GenerateConnectError ( error ) ;
return ;
}
string address ;
int port ;
NetworkID networkId ;
NodeID node ;
byte error2 ;
2018-06-22 18:34:35 +00:00
NetworkTransport . GetConnectionInfo ( s_ServerHostId , connectionId , out address , out port , out networkId , out node , out error2 ) ;
2018-06-22 13:18:23 +00:00
// add player info
NetworkConnection conn = ( NetworkConnection ) Activator . CreateInstance ( s_NetworkConnectionClass ) ;
2018-06-22 18:34:35 +00:00
conn . SetHandlers ( s_MessageHandlers ) ;
conn . Initialize ( address , s_ServerHostId , connectionId , s_HostTopology ) ;
2018-06-22 13:18:23 +00:00
conn . lastError = ( NetworkError ) error2 ;
// add connection at correct index
2018-06-22 18:34:35 +00:00
while ( s_Connections . Count < = connectionId )
2018-06-22 13:18:23 +00:00
{
2018-06-22 18:34:35 +00:00
s_Connections . Add ( null ) ;
2018-06-22 13:18:23 +00:00
}
2018-06-22 18:34:35 +00:00
s_Connections [ connectionId ] = conn ;
2018-06-22 13:18:23 +00:00
OnConnected ( conn ) ;
}
2018-06-22 18:34:35 +00:00
static void OnConnected ( NetworkConnection conn )
2018-06-07 13:41:08 +00:00
{
if ( LogFilter . logDebug ) { Debug . Log ( "Server accepted client:" + conn . connectionId ) ; }
2018-07-19 19:03:00 +00:00
conn . InvokeHandlerNoData ( ( short ) MsgType . Connect ) ;
2018-06-07 13:41:08 +00:00
}
2018-06-22 18:34:35 +00:00
static void HandleDisconnect ( int connectionId , byte error )
2018-06-22 13:18:23 +00:00
{
if ( LogFilter . logDebug ) { Debug . Log ( "Server disconnect client:" + connectionId ) ; }
var conn = FindConnection ( connectionId ) ;
if ( conn = = null )
{
return ;
}
conn . lastError = ( NetworkError ) error ;
if ( error ! = 0 )
{
if ( ( NetworkError ) error ! = NetworkError . Timeout )
{
2018-06-22 18:34:35 +00:00
s_Connections [ connectionId ] = null ;
2018-06-22 13:18:23 +00:00
if ( LogFilter . logError ) { Debug . LogError ( "Server client disconnect error, connectionId: " + connectionId + " error: " + ( NetworkError ) error ) ; }
return ;
}
}
conn . Disconnect ( ) ;
2018-06-22 18:34:35 +00:00
s_Connections [ connectionId ] = null ;
2018-06-22 13:18:23 +00:00
if ( LogFilter . logDebug ) { Debug . Log ( "Server lost client:" + connectionId ) ; }
OnDisconnected ( conn ) ;
}
2018-06-22 18:34:35 +00:00
static void OnDisconnected ( NetworkConnection conn )
2018-06-07 13:41:08 +00:00
{
2018-07-19 19:03:00 +00:00
conn . InvokeHandlerNoData ( ( short ) MsgType . Disconnect ) ;
2018-06-07 13:41:08 +00:00
2018-06-11 10:38:44 +00:00
if ( conn . playerControllers . Any ( pc = > pc . gameObject ! = null ) )
2018-06-07 13:41:08 +00:00
{
2018-06-11 10:38:44 +00:00
//NOTE: should there be default behaviour here to destroy the associated player?
if ( LogFilter . logWarn ) { Debug . LogWarning ( "Player not destroyed when connection disconnected." ) ; }
2018-06-07 13:41:08 +00:00
}
if ( LogFilter . logDebug ) { Debug . Log ( "Server lost client:" + conn . connectionId ) ; }
conn . RemoveObservers ( ) ;
conn . Dispose ( ) ;
}
2018-06-22 18:34:35 +00:00
public static NetworkConnection FindConnection ( int connectionId )
2018-06-22 13:18:23 +00:00
{
2018-06-22 18:34:35 +00:00
if ( connectionId < 0 | | connectionId > = s_Connections . Count )
2018-06-22 13:18:23 +00:00
return null ;
2018-06-22 18:34:35 +00:00
return s_Connections [ connectionId ] ;
2018-06-22 13:18:23 +00:00
}
2018-06-22 18:34:35 +00:00
static void HandleData ( int connectionId , int channelId , int receivedSize , byte error )
2018-06-22 13:18:23 +00:00
{
var conn = FindConnection ( connectionId ) ;
if ( conn = = null )
{
if ( LogFilter . logError ) { Debug . LogError ( "HandleData Unknown connectionId:" + connectionId ) ; }
return ;
}
conn . lastError = ( NetworkError ) error ;
if ( error ! = 0 )
{
GenerateDataError ( conn , error ) ;
return ;
}
OnData ( conn , receivedSize , channelId ) ;
}
2018-06-22 18:34:35 +00:00
static void OnData ( NetworkConnection conn , int receivedSize , int channelId )
2018-06-07 13:41:08 +00:00
{
#if UNITY_EDITOR
UnityEditor . NetworkDetailStats . IncrementStat (
UnityEditor . NetworkDetailStats . NetworkDirection . Incoming ,
2018-07-19 19:03:00 +00:00
( short ) MsgType . LLAPIMsg , "msg" , 1 ) ;
2018-06-07 13:41:08 +00:00
#endif
2018-06-22 18:34:35 +00:00
conn . TransportReceive ( s_MsgBuffer , receivedSize , channelId ) ;
2018-06-07 13:41:08 +00:00
}
2018-06-22 18:34:35 +00:00
static void GenerateConnectError ( byte error )
2018-06-07 13:41:08 +00:00
{
if ( LogFilter . logError ) { Debug . LogError ( "UNet Server Connect Error: " + error ) ; }
GenerateError ( null , error ) ;
}
2018-06-22 18:34:35 +00:00
static void GenerateDataError ( NetworkConnection conn , byte error )
2018-06-07 13:41:08 +00:00
{
NetworkError dataError = ( NetworkError ) error ;
if ( LogFilter . logError ) { Debug . LogError ( "UNet Server Data Error: " + dataError ) ; }
GenerateError ( conn , error ) ;
}
2018-06-22 18:34:35 +00:00
static void GenerateDisconnectError ( NetworkConnection conn , byte error )
2018-06-07 13:41:08 +00:00
{
NetworkError disconnectError = ( NetworkError ) error ;
if ( LogFilter . logError ) { Debug . LogError ( "UNet Server Disconnect Error: " + disconnectError + " conn:[" + conn + "]:" + conn . connectionId ) ; }
GenerateError ( conn , error ) ;
}
2018-06-22 18:34:35 +00:00
static void GenerateError ( NetworkConnection conn , byte error )
2018-06-07 13:41:08 +00:00
{
2018-07-19 19:03:00 +00:00
if ( handlers . ContainsKey ( ( short ) MsgType . Error ) )
2018-06-07 13:41:08 +00:00
{
ErrorMessage msg = new ErrorMessage ( ) ;
msg . errorCode = error ;
// write the message to a local buffer
NetworkWriter writer = new NetworkWriter ( ) ;
msg . Serialize ( writer ) ;
// pass a reader (attached to local buffer) to handler
2018-06-14 08:49:13 +00:00
NetworkReader reader = new NetworkReader ( writer . ToArray ( ) ) ;
2018-07-19 19:03:00 +00:00
conn . InvokeHandler ( ( short ) MsgType . Error , reader , 0 ) ;
2018-06-07 13:41:08 +00:00
}
}
static public void RegisterHandler ( short msgType , NetworkMessageDelegate handler )
{
2018-07-19 18:48:37 +00:00
if ( s_MessageHandlers . ContainsKey ( msgType ) )
{
if ( LogFilter . logDebug ) { Debug . Log ( "NetworkServer.RegisterHandler replacing " + msgType ) ; }
}
s_MessageHandlers [ msgType ] = handler ;
2018-06-07 13:41:08 +00:00
}
static public void UnregisterHandler ( short msgType )
{
2018-07-19 18:48:37 +00:00
s_MessageHandlers . Remove ( msgType ) ;
2018-06-07 13:41:08 +00:00
}
static public void ClearHandlers ( )
{
2018-07-19 18:48:37 +00:00
s_MessageHandlers . Clear ( ) ;
2018-06-07 13:41:08 +00:00
}
static public void ClearSpawners ( )
{
NetworkScene . ClearSpawners ( ) ;
}
// send this message to the player only
static public void SendToClientOfPlayer ( GameObject player , short msgType , MessageBase msg )
{
for ( int i = 0 ; i < connections . Count ; i + + )
{
var conn = connections [ i ] ;
if ( conn ! = null )
{
for ( int j = 0 ; j < conn . playerControllers . Count ; j + + )
{
if ( conn . playerControllers [ j ] . IsValid & & conn . playerControllers [ j ] . gameObject = = player )
{
conn . Send ( msgType , msg ) ;
return ;
}
}
}
}
if ( LogFilter . logError ) { Debug . LogError ( "Failed to send message to player object '" + player . name + ", not found in connection list" ) ; }
}
static public void SendToClient ( int connectionId , short msgType , MessageBase msg )
{
if ( connectionId < connections . Count )
{
var conn = connections [ connectionId ] ;
if ( conn ! = null )
{
conn . Send ( msgType , msg ) ;
return ;
}
}
if ( LogFilter . logError ) { Debug . LogError ( "Failed to send message to connection ID '" + connectionId + ", not found in connection list" ) ; }
}
static public bool ReplacePlayerForConnection ( NetworkConnection conn , GameObject player , short playerControllerId , NetworkHash128 assetId )
{
NetworkIdentity id ;
if ( GetNetworkIdentity ( player , out id ) )
{
id . SetDynamicAssetId ( assetId ) ;
}
2018-06-22 18:34:35 +00:00
return InternalReplacePlayerForConnection ( conn , player , playerControllerId ) ;
2018-06-07 13:41:08 +00:00
}
static public bool ReplacePlayerForConnection ( NetworkConnection conn , GameObject player , short playerControllerId )
{
2018-06-22 18:34:35 +00:00
return InternalReplacePlayerForConnection ( conn , player , playerControllerId ) ;
2018-06-07 13:41:08 +00:00
}
static public bool AddPlayerForConnection ( NetworkConnection conn , GameObject player , short playerControllerId , NetworkHash128 assetId )
{
NetworkIdentity id ;
if ( GetNetworkIdentity ( player , out id ) )
{
id . SetDynamicAssetId ( assetId ) ;
}
2018-06-22 18:34:35 +00:00
return InternalAddPlayerForConnection ( conn , player , playerControllerId ) ;
2018-06-07 13:41:08 +00:00
}
static public bool AddPlayerForConnection ( NetworkConnection conn , GameObject player , short playerControllerId )
{
2018-06-22 18:34:35 +00:00
return InternalAddPlayerForConnection ( conn , player , playerControllerId ) ;
2018-06-07 13:41:08 +00:00
}
2018-06-22 18:34:35 +00:00
static internal bool InternalAddPlayerForConnection ( NetworkConnection conn , GameObject playerGameObject , short playerControllerId )
2018-06-07 13:41:08 +00:00
{
NetworkIdentity playerNetworkIdentity ;
if ( ! GetNetworkIdentity ( playerGameObject , out playerNetworkIdentity ) )
{
if ( LogFilter . logError ) { Debug . Log ( "AddPlayer: playerGameObject has no NetworkIdentity. Please add a NetworkIdentity to " + playerGameObject ) ; }
return false ;
}
playerNetworkIdentity . Reset ( ) ;
if ( ! CheckPlayerControllerIdForConnection ( conn , playerControllerId ) )
return false ;
// cannot have a player object in "Add" version
PlayerController oldController = null ;
GameObject oldPlayer = null ;
if ( conn . GetPlayerController ( playerControllerId , out oldController ) )
{
oldPlayer = oldController . gameObject ;
}
if ( oldPlayer ! = null )
{
if ( LogFilter . logError ) { Debug . Log ( "AddPlayer: player object already exists for playerControllerId of " + playerControllerId ) ; }
return false ;
}
PlayerController newPlayerController = new PlayerController ( playerGameObject , playerControllerId ) ;
conn . SetPlayerController ( newPlayerController ) ;
// Set the playerControllerId on the NetworkIdentity on the server, NetworkIdentity.SetLocalPlayer is not called on the server (it is on clients and that sets the playerControllerId there)
playerNetworkIdentity . SetConnectionToClient ( conn , newPlayerController . playerControllerId ) ;
SetClientReady ( conn ) ;
if ( SetupLocalPlayerForConnection ( conn , playerNetworkIdentity , newPlayerController ) )
{
return true ;
}
if ( LogFilter . logDebug ) { Debug . Log ( "Adding new playerGameObject object netId: " + playerGameObject . GetComponent < NetworkIdentity > ( ) . netId + " asset ID " + playerGameObject . GetComponent < NetworkIdentity > ( ) . assetId ) ; }
FinishPlayerForConnection ( conn , playerNetworkIdentity , playerGameObject ) ;
if ( playerNetworkIdentity . localPlayerAuthority )
{
playerNetworkIdentity . SetClientOwner ( conn ) ;
}
return true ;
}
static bool CheckPlayerControllerIdForConnection ( NetworkConnection conn , short playerControllerId )
{
if ( playerControllerId < 0 )
{
if ( LogFilter . logError ) { Debug . LogError ( "AddPlayer: playerControllerId of " + playerControllerId + " is negative" ) ; }
return false ;
}
if ( playerControllerId > PlayerController . MaxPlayersPerClient )
{
if ( LogFilter . logError ) { Debug . Log ( "AddPlayer: playerControllerId of " + playerControllerId + " is too high. max is " + PlayerController . MaxPlayersPerClient ) ; }
return false ;
}
if ( playerControllerId > PlayerController . MaxPlayersPerClient / 2 )
{
if ( LogFilter . logWarn ) { Debug . LogWarning ( "AddPlayer: playerControllerId of " + playerControllerId + " is unusually high" ) ; }
}
return true ;
}
2018-06-22 18:34:35 +00:00
static bool SetupLocalPlayerForConnection ( NetworkConnection conn , NetworkIdentity uv , PlayerController newPlayerController )
2018-06-07 13:41:08 +00:00
{
if ( LogFilter . logDev ) { Debug . Log ( "NetworkServer SetupLocalPlayerForConnection netID:" + uv . netId ) ; }
var localConnection = conn as ULocalConnectionToClient ;
if ( localConnection ! = null )
{
if ( LogFilter . logDev ) { Debug . Log ( "NetworkServer AddPlayer handling ULocalConnectionToClient" ) ; }
// Spawn this player for other players, instead of SpawnObject:
if ( uv . netId . IsEmpty ( ) )
{
// it is allowed to provide an already spawned object as the new player object.
// so dont spawn it again.
uv . OnStartServer ( true ) ;
}
uv . RebuildObservers ( true ) ;
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 ) ;
// Trigger OnStartLocalPlayer
uv . SetLocalPlayer ( newPlayerController . playerControllerId ) ;
return true ;
}
return false ;
}
static void FinishPlayerForConnection ( NetworkConnection conn , NetworkIdentity uv , GameObject playerGameObject )
{
if ( uv . netId . IsEmpty ( ) )
{
// it is allowed to provide an already spawned object as the new player object.
// so dont spawn it again.
Spawn ( playerGameObject ) ;
}
OwnerMessage owner = new OwnerMessage ( ) ;
owner . netId = uv . netId ;
owner . playerControllerId = uv . playerControllerId ;
2018-07-19 19:03:00 +00:00
conn . Send ( ( short ) MsgType . Owner , owner ) ;
2018-06-07 13:41:08 +00:00
}
2018-06-22 18:34:35 +00:00
static internal bool InternalReplacePlayerForConnection ( NetworkConnection conn , GameObject playerGameObject , short playerControllerId )
2018-06-07 13:41:08 +00:00
{
NetworkIdentity playerNetworkIdentity ;
if ( ! GetNetworkIdentity ( playerGameObject , out playerNetworkIdentity ) )
{
if ( LogFilter . logError ) { Debug . LogError ( "ReplacePlayer: playerGameObject has no NetworkIdentity. Please add a NetworkIdentity to " + playerGameObject ) ; }
return false ;
}
if ( ! CheckPlayerControllerIdForConnection ( conn , playerControllerId ) )
return false ;
//NOTE: there can be an existing player
if ( LogFilter . logDev ) { Debug . Log ( "NetworkServer ReplacePlayer" ) ; }
// is there already an owner that is a different object??
PlayerController oldOwner ;
if ( conn . GetPlayerController ( playerControllerId , out oldOwner ) )
{
oldOwner . unetView . SetNotLocalPlayer ( ) ;
oldOwner . unetView . ClearClientOwner ( ) ;
}
PlayerController newPlayerController = new PlayerController ( playerGameObject , playerControllerId ) ;
conn . SetPlayerController ( newPlayerController ) ;
// Set the playerControllerId on the NetworkIdentity on the server, NetworkIdentity.SetLocalPlayer is not called on the server (it is on clients and that sets the playerControllerId there)
playerNetworkIdentity . SetConnectionToClient ( conn , newPlayerController . playerControllerId ) ;
//NOTE: DONT set connection ready.
if ( LogFilter . logDev ) { Debug . Log ( "NetworkServer ReplacePlayer setup local" ) ; }
if ( SetupLocalPlayerForConnection ( conn , playerNetworkIdentity , newPlayerController ) )
{
return true ;
}
if ( LogFilter . logDebug ) { Debug . Log ( "Replacing playerGameObject object netId: " + playerGameObject . GetComponent < NetworkIdentity > ( ) . netId + " asset ID " + playerGameObject . GetComponent < NetworkIdentity > ( ) . assetId ) ; }
FinishPlayerForConnection ( conn , playerNetworkIdentity , playerGameObject ) ;
if ( playerNetworkIdentity . localPlayerAuthority )
{
playerNetworkIdentity . SetClientOwner ( conn ) ;
}
return true ;
}
static bool GetNetworkIdentity ( GameObject go , out NetworkIdentity view )
{
view = go . GetComponent < NetworkIdentity > ( ) ;
if ( view = = null )
{
if ( LogFilter . logError ) { Debug . LogError ( "UNET failure. GameObject doesn't have NetworkIdentity." ) ; }
return false ;
}
return true ;
}
static public void SetClientReady ( NetworkConnection conn )
{
2018-06-22 18:34:35 +00:00
SetClientReadyInternal ( conn ) ;
2018-06-07 13:41:08 +00:00
}
2018-06-22 18:34:35 +00:00
static internal void SetClientReadyInternal ( NetworkConnection conn )
2018-06-07 13:41:08 +00:00
{
if ( LogFilter . logDebug ) { Debug . Log ( "SetClientReadyInternal for conn:" + conn . connectionId ) ; }
if ( conn . isReady )
{
if ( LogFilter . logDebug ) { Debug . Log ( "SetClientReady conn " + conn . connectionId + " already ready" ) ; }
return ;
}
if ( conn . playerControllers . Count = = 0 )
{
// this is now allowed
if ( LogFilter . logDebug ) { Debug . LogWarning ( "Ready with no player object" ) ; }
}
conn . isReady = true ;
var localConnection = conn as ULocalConnectionToClient ;
if ( localConnection ! = null )
{
if ( LogFilter . logDev ) { Debug . Log ( "NetworkServer Ready handling ULocalConnectionToClient" ) ; }
// Setup spawned objects for local player
// Only handle the local objects for the first player (no need to redo it when doing more local players)
// and don't handle player objects here, they were done above
foreach ( NetworkIdentity uv in objects . Values )
{
// Need to call OnStartClient directly here, as it's already been added to the local object dictionary
// in the above SetLocalPlayer call
if ( uv ! = null & & uv . gameObject ! = null )
{
var vis = uv . OnCheckObserver ( conn ) ;
if ( vis )
{
uv . AddObserver ( conn ) ;
}
if ( ! uv . isClient )
{
if ( LogFilter . logDev ) { Debug . Log ( "LocalClient.SetSpawnObject calling OnStartClient" ) ; }
uv . OnStartClient ( ) ;
}
}
}
return ;
}
// Spawn/update all current server objects
if ( LogFilter . logDebug ) { Debug . Log ( "Spawning " + objects . Count + " objects for conn " + conn . connectionId ) ; }
ObjectSpawnFinishedMessage msg = new ObjectSpawnFinishedMessage ( ) ;
msg . state = 0 ;
2018-07-19 19:03:00 +00:00
conn . Send ( ( short ) MsgType . SpawnFinished , msg ) ;
2018-06-07 13:41:08 +00:00
foreach ( NetworkIdentity uv in objects . Values )
{
if ( uv = = null )
{
if ( LogFilter . logWarn ) { Debug . LogWarning ( "Invalid object found in server local object list (null NetworkIdentity)." ) ; }
continue ;
}
if ( ! uv . gameObject . activeSelf )
{
continue ;
}
if ( LogFilter . logDebug ) { Debug . Log ( "Sending spawn message for current server objects name='" + uv . gameObject . name + "' netId=" + uv . netId ) ; }
var vis = uv . OnCheckObserver ( conn ) ;
if ( vis )
{
uv . AddObserver ( conn ) ;
}
}
msg . state = 1 ;
2018-07-19 19:03:00 +00:00
conn . Send ( ( short ) MsgType . SpawnFinished , msg ) ;
2018-06-07 13:41:08 +00:00
}
static internal void ShowForConnection ( NetworkIdentity uv , NetworkConnection conn )
{
if ( conn . isReady )
2018-06-22 18:34:35 +00:00
SendSpawnMessage ( uv , conn ) ;
2018-06-07 13:41:08 +00:00
}
static internal void HideForConnection ( NetworkIdentity uv , NetworkConnection conn )
{
ObjectDestroyMessage msg = new ObjectDestroyMessage ( ) ;
msg . netId = uv . netId ;
2018-07-19 19:03:00 +00:00
conn . Send ( ( short ) MsgType . ObjectHide , msg ) ;
2018-06-07 13:41:08 +00:00
}
// call this to make all the clients not ready, such as when changing levels.
static public void SetAllClientsNotReady ( )
{
for ( int i = 0 ; i < connections . Count ; i + + )
{
var conn = connections [ i ] ;
if ( conn ! = null )
{
SetClientNotReady ( conn ) ;
}
}
}
static public void SetClientNotReady ( NetworkConnection conn )
{
2018-06-22 18:34:35 +00:00
InternalSetClientNotReady ( conn ) ;
2018-06-07 13:41:08 +00:00
}
2018-06-22 18:34:35 +00:00
static internal void InternalSetClientNotReady ( NetworkConnection conn )
2018-06-07 13:41:08 +00:00
{
if ( conn . isReady )
{
if ( LogFilter . logDebug ) { Debug . Log ( "PlayerNotReady " + conn ) ; }
conn . isReady = false ;
conn . RemoveObservers ( ) ;
NotReadyMessage msg = new NotReadyMessage ( ) ;
2018-07-19 19:03:00 +00:00
conn . Send ( ( short ) MsgType . NotReady , msg ) ;
2018-06-07 13:41:08 +00:00
}
}
// default ready handler.
static void OnClientReadyMessage ( NetworkMessage netMsg )
{
if ( LogFilter . logDebug ) { Debug . Log ( "Default handler for ready message from " + netMsg . conn ) ; }
SetClientReady ( netMsg . conn ) ;
}
// default remove player handler
static void OnRemovePlayerMessage ( NetworkMessage netMsg )
{
2018-06-10 08:15:54 +00:00
RemovePlayerMessage msg = new RemovePlayerMessage ( ) ;
netMsg . ReadMessage ( msg ) ;
2018-06-07 13:41:08 +00:00
PlayerController player = null ;
2018-06-10 08:15:54 +00:00
netMsg . conn . GetPlayerController ( msg . playerControllerId , out player ) ;
2018-06-07 13:41:08 +00:00
if ( player ! = null )
{
2018-06-10 08:15:54 +00:00
netMsg . conn . RemovePlayerController ( msg . playerControllerId ) ;
2018-06-07 13:41:08 +00:00
Destroy ( player . gameObject ) ;
}
else
{
2018-06-10 08:15:54 +00:00
if ( LogFilter . logError ) { Debug . LogError ( "Received remove player message but could not find the player ID: " + msg . playerControllerId ) ; }
2018-06-07 13:41:08 +00:00
}
}
// Handle command from specific player, this could be one of multiple players on a single client
static void OnCommandMessage ( NetworkMessage netMsg )
{
int cmdHash = ( int ) netMsg . reader . ReadPackedUInt32 ( ) ;
var netId = netMsg . reader . ReadNetworkId ( ) ;
var cmdObject = FindLocalObject ( netId ) ;
if ( cmdObject = = null )
{
if ( LogFilter . logWarn ) { Debug . LogWarning ( "Instance not found when handling Command message [netId=" + netId + "]" ) ; }
return ;
}
var uv = cmdObject . GetComponent < NetworkIdentity > ( ) ;
if ( uv = = null )
{
if ( LogFilter . logWarn ) { Debug . LogWarning ( "NetworkIdentity deleted when handling Command message [netId=" + netId + "]" ) ; }
return ;
}
// Commands can be for player objects, OR other objects with client-authority
2018-06-11 10:38:44 +00:00
// => check if there is no owner
if ( ! netMsg . conn . playerControllers . Any (
pc = > pc . gameObject ! = null & &
pc . gameObject . GetComponent < NetworkIdentity > ( ) . netId = = uv . netId ) )
2018-06-07 13:41:08 +00:00
{
if ( uv . clientAuthorityOwner ! = netMsg . conn )
{
if ( LogFilter . logWarn ) { Debug . LogWarning ( "Command for object without authority [netId=" + netId + "]" ) ; }
return ;
}
}
if ( LogFilter . logDev ) { Debug . Log ( "OnCommandMessage for netId=" + netId + " conn=" + netMsg . conn ) ; }
uv . HandleCommand ( cmdHash , netMsg . reader ) ;
}
2018-06-22 18:34:35 +00:00
static internal void SpawnObject ( GameObject obj )
2018-06-07 13:41:08 +00:00
{
if ( ! NetworkServer . active )
{
if ( LogFilter . logError ) { Debug . LogError ( "SpawnObject for " + obj + ", NetworkServer is not active. Cannot spawn objects without an active server." ) ; }
return ;
}
NetworkIdentity objNetworkIdentity ;
if ( ! GetNetworkIdentity ( obj , out objNetworkIdentity ) )
{
if ( LogFilter . logError ) { Debug . LogError ( "SpawnObject " + obj + " has no NetworkIdentity. Please add a NetworkIdentity to " + obj ) ; }
return ;
}
objNetworkIdentity . Reset ( ) ;
objNetworkIdentity . OnStartServer ( false ) ;
if ( LogFilter . logDebug ) { Debug . Log ( "SpawnObject instance ID " + objNetworkIdentity . netId + " asset ID " + objNetworkIdentity . assetId ) ; }
objNetworkIdentity . RebuildObservers ( true ) ;
//SendSpawnMessage(objNetworkIdentity, null);
}
2018-06-22 18:34:35 +00:00
static internal void SendSpawnMessage ( NetworkIdentity uv , NetworkConnection conn )
2018-06-07 13:41:08 +00:00
{
if ( uv . serverOnly )
return ;
2018-06-08 08:59:32 +00:00
if ( LogFilter . logDebug ) { Debug . Log ( "Server SendSpawnMessage: name=" + uv . name + " sceneId=" + uv . sceneId + " netid=" + uv . netId ) ; } // for easier debugging
2018-06-07 13:41:08 +00:00
if ( uv . sceneId . IsEmpty ( ) )
{
ObjectSpawnMessage msg = new ObjectSpawnMessage ( ) ;
msg . netId = uv . netId ;
msg . assetId = uv . assetId ;
msg . position = uv . transform . position ;
msg . rotation = uv . transform . rotation ;
// include synch data
NetworkWriter writer = new NetworkWriter ( ) ;
uv . UNetSerializeAllVars ( writer ) ;
2018-07-20 10:57:15 +00:00
msg . payload = writer . ToArray ( ) ;
2018-06-07 13:41:08 +00:00
if ( conn ! = null )
{
2018-07-19 19:03:00 +00:00
conn . Send ( ( short ) MsgType . ObjectSpawn , msg ) ;
2018-06-07 13:41:08 +00:00
}
else
{
2018-07-19 19:03:00 +00:00
SendToReady ( uv . gameObject , ( short ) MsgType . ObjectSpawn , msg ) ;
2018-06-07 13:41:08 +00:00
}
#if UNITY_EDITOR
UnityEditor . NetworkDetailStats . IncrementStat (
UnityEditor . NetworkDetailStats . NetworkDirection . Outgoing ,
2018-07-19 19:03:00 +00:00
( short ) MsgType . ObjectSpawn , uv . assetId . ToString ( ) , 1 ) ;
2018-06-07 13:41:08 +00:00
#endif
}
else
{
ObjectSpawnSceneMessage msg = new ObjectSpawnSceneMessage ( ) ;
msg . netId = uv . netId ;
msg . sceneId = uv . sceneId ;
msg . position = uv . transform . position ;
// include synch data
NetworkWriter writer = new NetworkWriter ( ) ;
uv . UNetSerializeAllVars ( writer ) ;
2018-07-20 10:57:15 +00:00
msg . payload = writer . ToArray ( ) ;
2018-06-07 13:41:08 +00:00
if ( conn ! = null )
{
2018-07-19 19:03:00 +00:00
conn . Send ( ( short ) MsgType . ObjectSpawnScene , msg ) ;
2018-06-07 13:41:08 +00:00
}
else
{
2018-07-19 19:03:00 +00:00
SendToReady ( uv . gameObject , ( short ) MsgType . ObjectSpawn , msg ) ;
2018-06-07 13:41:08 +00:00
}
#if UNITY_EDITOR
UnityEditor . NetworkDetailStats . IncrementStat (
UnityEditor . NetworkDetailStats . NetworkDirection . Outgoing ,
2018-07-19 19:03:00 +00:00
( short ) MsgType . ObjectSpawnScene , "sceneId" , 1 ) ;
2018-06-07 13:41:08 +00:00
#endif
}
}
static public void DestroyPlayersForConnection ( NetworkConnection conn )
{
if ( conn . playerControllers . Count = = 0 )
{
2018-06-13 09:24:41 +00:00
// list is empty if players are still in a lobby etc., no need to show a warning
2018-06-07 13:41:08 +00:00
return ;
}
if ( conn . clientOwnedObjects ! = null )
{
var tmp = new HashSet < NetworkInstanceId > ( conn . clientOwnedObjects ) ;
foreach ( var netId in tmp )
{
var obj = FindLocalObject ( netId ) ;
if ( obj ! = null )
{
DestroyObject ( obj ) ;
}
}
}
for ( int i = 0 ; i < conn . playerControllers . Count ; i + + )
{
var player = conn . playerControllers [ i ] ;
if ( player . IsValid )
{
if ( player . unetView = = null )
{
// the playerController's object has been destroyed, but RemovePlayerForConnection was never called.
// this is ok, just dont double destroy it.
}
else
{
DestroyObject ( player . unetView , true ) ;
}
player . gameObject = null ;
}
}
conn . playerControllers . Clear ( ) ;
}
static void UnSpawnObject ( GameObject obj )
{
if ( obj = = null )
{
if ( LogFilter . logDev ) { Debug . Log ( "NetworkServer UnspawnObject is null" ) ; }
return ;
}
NetworkIdentity objNetworkIdentity ;
if ( ! GetNetworkIdentity ( obj , out objNetworkIdentity ) ) return ;
UnSpawnObject ( objNetworkIdentity ) ;
}
static void UnSpawnObject ( NetworkIdentity uv )
{
DestroyObject ( uv , false ) ;
}
static void DestroyObject ( GameObject obj )
{
if ( obj = = null )
{
if ( LogFilter . logDev ) { Debug . Log ( "NetworkServer DestroyObject is null" ) ; }
return ;
}
NetworkIdentity objNetworkIdentity ;
if ( ! GetNetworkIdentity ( obj , out objNetworkIdentity ) ) return ;
DestroyObject ( objNetworkIdentity , true ) ;
}
static void DestroyObject ( NetworkIdentity uv , bool destroyServerObject )
{
if ( LogFilter . logDebug ) { Debug . Log ( "DestroyObject instance:" + uv . netId ) ; }
if ( objects . ContainsKey ( uv . netId ) )
{
objects . Remove ( uv . netId ) ;
}
if ( uv . clientAuthorityOwner ! = null )
{
uv . clientAuthorityOwner . RemoveOwnedObject ( uv ) ;
}
#if UNITY_EDITOR
UnityEditor . NetworkDetailStats . IncrementStat (
UnityEditor . NetworkDetailStats . NetworkDirection . Outgoing ,
2018-07-19 19:03:00 +00:00
( short ) MsgType . ObjectDestroy , uv . assetId . ToString ( ) , 1 ) ;
2018-06-07 13:41:08 +00:00
#endif
ObjectDestroyMessage msg = new ObjectDestroyMessage ( ) ;
msg . netId = uv . netId ;
2018-07-19 19:03:00 +00:00
SendToObservers ( uv . gameObject , ( short ) MsgType . ObjectDestroy , msg ) ;
2018-06-07 13:41:08 +00:00
uv . ClearObservers ( ) ;
2018-06-22 13:18:23 +00:00
if ( NetworkClient . active & & s_LocalClientActive )
2018-06-07 13:41:08 +00:00
{
uv . OnNetworkDestroy ( ) ;
ClientScene . SetLocalObject ( msg . netId , null ) ;
}
// when unspawning, dont destroy the server's object
if ( destroyServerObject )
{
Object . Destroy ( uv . gameObject ) ;
}
uv . MarkForReset ( ) ;
}
static public void ClearLocalObjects ( )
{
objects . Clear ( ) ;
}
static public void Spawn ( GameObject obj )
{
2018-06-11 10:38:44 +00:00
if ( VerifyCanSpawn ( obj ) )
2018-06-07 13:41:08 +00:00
{
2018-06-22 18:34:35 +00:00
SpawnObject ( obj ) ;
2018-06-07 13:41:08 +00:00
}
}
static bool CheckForPrefab ( GameObject obj )
{
#if UNITY_EDITOR
return ( UnityEditor . PrefabUtility . GetPrefabParent ( obj ) = = null ) & & ( UnityEditor . PrefabUtility . GetPrefabObject ( obj ) ! = null ) ;
#else
return false ;
#endif
}
static bool VerifyCanSpawn ( GameObject obj )
{
if ( CheckForPrefab ( obj ) )
{
Debug . LogErrorFormat ( "GameObject {0} is a prefab, it can't be spawned. This will cause errors in builds." , obj . name ) ;
return false ;
}
return true ;
}
static public Boolean SpawnWithClientAuthority ( GameObject obj , GameObject player )
{
var uv = player . GetComponent < NetworkIdentity > ( ) ;
if ( uv = = null )
{
Debug . LogError ( "SpawnWithClientAuthority player object has no NetworkIdentity" ) ;
return false ;
}
if ( uv . connectionToClient = = null )
{
Debug . LogError ( "SpawnWithClientAuthority player object is not a player." ) ;
return false ;
}
return SpawnWithClientAuthority ( obj , uv . connectionToClient ) ;
}
static public bool SpawnWithClientAuthority ( GameObject obj , NetworkConnection conn )
{
if ( ! conn . isReady )
{
Debug . LogError ( "SpawnWithClientAuthority NetworkConnection is not ready!" ) ;
return false ;
}
Spawn ( obj ) ;
var uv = obj . GetComponent < NetworkIdentity > ( ) ;
if ( uv = = null | | ! uv . isServer )
{
// spawning the object failed.
return false ;
}
return uv . AssignClientAuthority ( conn ) ;
}
static public bool SpawnWithClientAuthority ( GameObject obj , NetworkHash128 assetId , NetworkConnection conn )
{
Spawn ( obj , assetId ) ;
var uv = obj . GetComponent < NetworkIdentity > ( ) ;
if ( uv = = null | | ! uv . isServer )
{
// spawning the object failed.
return false ;
}
return uv . AssignClientAuthority ( conn ) ;
}
static public void Spawn ( GameObject obj , NetworkHash128 assetId )
{
2018-06-11 10:38:44 +00:00
if ( VerifyCanSpawn ( obj ) )
2018-06-07 13:41:08 +00:00
{
2018-06-11 10:38:44 +00:00
NetworkIdentity id ;
if ( GetNetworkIdentity ( obj , out id ) )
{
id . SetDynamicAssetId ( assetId ) ;
}
2018-06-22 18:34:35 +00:00
SpawnObject ( obj ) ;
2018-06-07 13:41:08 +00:00
}
}
static public void Destroy ( GameObject obj )
{
DestroyObject ( obj ) ;
}
static public void UnSpawn ( GameObject obj )
{
UnSpawnObject ( obj ) ;
}
2018-07-20 10:29:51 +00:00
static internal bool InvokeBytes ( ULocalConnectionToServer conn , byte [ ] buffer , int channelId )
2018-06-07 13:41:08 +00:00
{
NetworkReader reader = new NetworkReader ( buffer ) ;
reader . ReadInt16 ( ) ; // size
short msgType = reader . ReadInt16 ( ) ;
2018-06-22 18:34:35 +00:00
if ( handlers . ContainsKey ( msgType ) & & s_LocalConnection ! = null )
2018-06-07 13:41:08 +00:00
{
// this must be invoked with the connection to the client, not the client's connection to the server
2018-06-22 18:34:35 +00:00
s_LocalConnection . InvokeHandler ( msgType , reader , channelId ) ;
2018-06-07 13:41:08 +00:00
return true ;
}
return false ;
}
// invoked for local clients
2018-06-22 18:34:35 +00:00
static internal bool InvokeHandlerOnServer ( ULocalConnectionToServer conn , short msgType , MessageBase msg , int channelId )
2018-06-07 13:41:08 +00:00
{
2018-06-22 18:34:35 +00:00
if ( handlers . ContainsKey ( msgType ) & & s_LocalConnection ! = null )
2018-06-07 13:41:08 +00:00
{
// write the message to a local buffer
NetworkWriter writer = new NetworkWriter ( ) ;
msg . Serialize ( writer ) ;
// pass a reader (attached to local buffer) to handler
2018-06-14 08:49:13 +00:00
NetworkReader reader = new NetworkReader ( writer . ToArray ( ) ) ;
2018-06-07 13:41:08 +00:00
// this must be invoked with the connection to the client, not the client's connection to the server
2018-06-22 18:34:35 +00:00
s_LocalConnection . InvokeHandler ( msgType , reader , channelId ) ;
2018-06-07 13:41:08 +00:00
return true ;
}
if ( LogFilter . logError ) { Debug . LogError ( "Local invoke: Failed to find local connection to invoke handler on [connectionId=" + conn . connectionId + "] for MsgId:" + msgType ) ; }
return false ;
}
static public GameObject FindLocalObject ( NetworkInstanceId netId )
{
2018-06-22 13:18:23 +00:00
return s_NetworkScene . FindLocalObject ( netId ) ;
2018-06-07 13:41:08 +00:00
}
static public bool AddExternalConnection ( NetworkConnection conn )
{
2018-06-22 18:34:35 +00:00
return AddExternalConnectionInternal ( conn ) ;
2018-06-07 13:41:08 +00:00
}
2018-06-22 18:34:35 +00:00
static bool AddExternalConnectionInternal ( NetworkConnection conn )
2018-06-07 13:41:08 +00:00
{
if ( conn . connectionId < 0 )
return false ;
if ( conn . connectionId < connections . Count & & connections [ conn . connectionId ] ! = null )
{
if ( LogFilter . logError ) { Debug . LogError ( "AddExternalConnection failed, already connection for id:" + conn . connectionId ) ; }
return false ;
}
if ( LogFilter . logDebug ) { Debug . Log ( "AddExternalConnection external connection " + conn . connectionId ) ; }
2018-06-22 13:18:23 +00:00
SetConnectionAtIndex ( conn ) ;
s_ExternalConnections . Add ( conn . connectionId ) ;
2018-07-19 19:03:00 +00:00
conn . InvokeHandlerNoData ( ( short ) MsgType . Connect ) ;
2018-06-07 13:41:08 +00:00
return true ;
}
static public void RemoveExternalConnection ( int connectionId )
{
2018-06-22 18:34:35 +00:00
RemoveExternalConnectionInternal ( connectionId ) ;
2018-06-07 13:41:08 +00:00
}
2018-06-22 18:34:35 +00:00
static bool RemoveExternalConnectionInternal ( int connectionId )
2018-06-07 13:41:08 +00:00
{
2018-06-22 13:18:23 +00:00
if ( ! s_ExternalConnections . Contains ( connectionId ) )
2018-06-07 13:41:08 +00:00
{
if ( LogFilter . logError ) { Debug . LogError ( "RemoveExternalConnection failed, no connection for id:" + connectionId ) ; }
return false ;
}
if ( LogFilter . logDebug ) { Debug . Log ( "RemoveExternalConnection external connection " + connectionId ) ; }
2018-06-22 13:18:23 +00:00
var conn = FindConnection ( connectionId ) ;
2018-06-07 13:41:08 +00:00
if ( conn ! = null )
{
conn . RemoveObservers ( ) ;
}
2018-06-22 18:34:35 +00:00
s_Connections . RemoveAt ( connectionId ) ;
2018-06-07 13:41:08 +00:00
return true ;
}
static bool ValidateSceneObject ( NetworkIdentity netId )
{
if ( netId . gameObject . hideFlags = = HideFlags . NotEditable | | netId . gameObject . hideFlags = = HideFlags . HideAndDontSave )
return false ;
#if UNITY_EDITOR
if ( UnityEditor . EditorUtility . IsPersistent ( netId . gameObject ) )
return false ;
#endif
// If not a scene object
if ( netId . sceneId . IsEmpty ( ) )
return false ;
return true ;
}
static public bool SpawnObjects ( )
{
if ( ! active )
return true ;
NetworkIdentity [ ] netIds = Resources . FindObjectsOfTypeAll < NetworkIdentity > ( ) ;
for ( int i = 0 ; i < netIds . Length ; i + + )
{
var netId = netIds [ i ] ;
if ( ! ValidateSceneObject ( netId ) )
continue ;
if ( LogFilter . logDebug ) { Debug . Log ( "SpawnObjects sceneId:" + netId . sceneId + " name:" + netId . gameObject . name ) ; }
netId . Reset ( ) ;
netId . gameObject . SetActive ( true ) ;
}
for ( int i = 0 ; i < netIds . Length ; i + + )
{
var netId = netIds [ i ] ;
if ( ! ValidateSceneObject ( netId ) )
continue ;
Spawn ( netId . gameObject ) ;
// these objects are server authority - even if "localPlayerAuthority" is set on them
netId . ForceAuthority ( true ) ;
}
return true ;
}
} ;
}
#endif //ENABLE_UNET