1
0
forked from cgvr/DeltaVR

deltavr multiplayer 2.0

This commit is contained in:
Toomas Tamm
2023-05-08 15:56:10 +03:00
parent 978809a002
commit 07b9b9e2f4
10937 changed files with 2968397 additions and 1521012 deletions

View File

@@ -0,0 +1,61 @@
# This .gitignore file should be placed at the root of your Unity project directory
#
# Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore
#
/[Ll]ibrary/
/[Tt]emp/
/[Oo]bj/
/[Bb]uild/
/[Bb]uilds/
/[Ll]ogs/
/[Mm]emoryCaptures/
# Asset meta data should only be ignored when the corresponding asset is also ignored
!/[Aa]ssets/**/*.meta
# Uncomment this line if you wish to ignore the asset store tools plugin
# /[Aa]ssets/AssetStoreTools*
# Autogenerated Jetbrains Rider plugin
[Aa]ssets/Plugins/Editor/JetBrains*
# Visual Studio cache directory
.vs/
# Gradle cache directory
.gradle/
# Autogenerated VS/MD/Consulo solution and project files
ExportedObj/
.consulo/
*.csproj
*.unityproj
*.sln
*.suo
*.tmp
*.user
*.userprefs
*.pidb
*.booproj
*.svd
*.pdb
*.mdb
*.opendb
*.VC.db
# Unity3D generated meta files
*.pidb.meta
*.pdb.meta
*.mdb.meta
*.meta
# Unity3D generated file on crash reports
sysinfo.txt
# Builds
*.apk
*.unitypackage
# Crashlytics generated file
crashlytics-build.properties

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Winterbolt Games
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,306 @@
using FishNet.Managing;
using FishNet.Managing.Logging;
using FishNet.Transporting;
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace FishNet.Discovery
{
/// <summary>
/// A component that advertises a server or searches for servers.
/// </summary>
public sealed class NetworkDiscovery : MonoBehaviour
{
/// <summary>
/// A string that differentiates your application/game from others.
/// <b>Must not</b> be null, empty, or blank.
/// </summary>
[SerializeField]
[Tooltip("A string that differentiates your application/game from others. Must not be null, empty, or blank.")]
private string secret;
/// <summary>
/// The port number used by this <see cref="NetworkDiscovery"/> component.
/// <b>Must</b> be different from the one used by the <seealso cref="Transport"/>.
/// </summary>
[SerializeField]
[Tooltip("The port number used by this NetworkDiscovery component. Must be different from the one used by the Transport.")]
private ushort port;
/// <summary>
/// How often does this <see cref="NetworkDiscovery"/> component advertises a server or searches for servers.
/// </summary>
[SerializeField]
[Tooltip("How often does this NetworkDiscovery component advertises a server or searches for servers.")]
private float discoveryInterval;
/// <summary>
/// Whether this <see cref="NetworkDiscovery"/> component will automatically start/stop? <b>Setting this to true is recommended.</b>
/// </summary>
[SerializeField]
[Tooltip("Whether this NetworkDiscovery component will automatically start/stop? Setting this to true is recommended.")]
private bool automatic;
/// <summary>
/// The <see cref="UdpClient"/> used to advertise the server.
/// </summary>
private UdpClient _serverUdpClient;
/// <summary>
/// The <see cref="UdpClient"/> used to search for servers.
/// </summary>
private UdpClient _clientUdpClient;
/// <summary>
/// Whether this <see cref="NetworkDiscovery"/> component is currently advertising a server or not.
/// </summary>
public bool IsAdvertising => _serverUdpClient != null;
/// <summary>
/// Whether this <see cref="NetworkDiscovery"/> component is currently searching for servers or not.
/// </summary>
public bool IsSearching => _clientUdpClient != null;
/// <summary>
/// An <see cref="Action"/> that is invoked by this <seealso cref="NetworkDiscovery"/> component whenever a server is found.
/// </summary>
public event Action<IPEndPoint> ServerFoundCallback;
private void Start()
{
if (automatic)
{
InstanceFinder.ServerManager.OnServerConnectionState += ServerConnectionStateChangedHandler;
InstanceFinder.ClientManager.OnClientConnectionState += ClientConnectionStateChangedHandler;
StartSearchingForServers();
}
}
private void OnDisable()
{
InstanceFinder.ServerManager.OnServerConnectionState -= ServerConnectionStateChangedHandler;
InstanceFinder.ClientManager.OnClientConnectionState -= ClientConnectionStateChangedHandler;
StopAdvertisingServer();
StopSearchingForServers();
}
private void OnDestroy()
{
InstanceFinder.ServerManager.OnServerConnectionState -= ServerConnectionStateChangedHandler;
InstanceFinder.ClientManager.OnClientConnectionState -= ClientConnectionStateChangedHandler;
StopAdvertisingServer();
StopSearchingForServers();
}
private void OnApplicationQuit()
{
InstanceFinder.ServerManager.OnServerConnectionState -= ServerConnectionStateChangedHandler;
InstanceFinder.ClientManager.OnClientConnectionState -= ClientConnectionStateChangedHandler;
StopAdvertisingServer();
StopSearchingForServers();
}
#region Connection State Handlers
private void ServerConnectionStateChangedHandler(ServerConnectionStateArgs args)
{
if (args.ConnectionState == LocalConnectionState.Starting)
{
StopSearchingForServers();
}
else if (args.ConnectionState == LocalConnectionState.Started)
{
StartAdvertisingServer();
}
else if (args.ConnectionState == LocalConnectionState.Stopping)
{
//StopAdvertisingServer();
}
else if (args.ConnectionState == LocalConnectionState.Stopped)
{
StartSearchingForServers();
}
}
private void ClientConnectionStateChangedHandler(ClientConnectionStateArgs args)
{
if (args.ConnectionState == LocalConnectionState.Starting)
{
StopSearchingForServers();
}
else if (args.ConnectionState == LocalConnectionState.Stopped)
{
StartSearchingForServers();
}
}
#endregion
#region Server
/// <summary>
/// Makes this <see cref="NetworkDiscovery"/> component start advertising a server.
/// </summary>
public void StartAdvertisingServer()
{
if (!InstanceFinder.IsServer)
{
if (NetworkManager.StaticCanLog(LoggingType.Warning)) Debug.LogWarning("Unable to start advertising server. Server is inactive.", this);
return;
}
if (_serverUdpClient != null)
{
if (NetworkManager.StaticCanLog(LoggingType.Common)) Debug.Log("Server is already being advertised.", this);
return;
}
if (port == InstanceFinder.TransportManager.Transport.GetPort())
{
if (NetworkManager.StaticCanLog(LoggingType.Warning)) Debug.LogWarning("Unable to start advertising server on the same port as the transport.", this);
return;
}
_serverUdpClient = new UdpClient(port)
{
EnableBroadcast = true,
MulticastLoopback = false,
};
Task.Run(AdvertiseServerAsync);
if (NetworkManager.StaticCanLog(LoggingType.Common)) Debug.Log("Started advertising server.", this);
}
/// <summary>
/// Makes this <see cref="NetworkDiscovery"/> component <i>immediately</i> stop advertising the server it is currently advertising.
/// </summary>
public void StopAdvertisingServer()
{
if (_serverUdpClient == null) return;
_serverUdpClient.Close();
_serverUdpClient = null;
if (NetworkManager.StaticCanLog(LoggingType.Common)) Debug.Log("Stopped advertising server.", this);
}
private async void AdvertiseServerAsync()
{
while (_serverUdpClient != null)
{
await Task.Delay(TimeSpan.FromSeconds(discoveryInterval));
UdpReceiveResult result = await _serverUdpClient.ReceiveAsync();
string receivedSecret = Encoding.UTF8.GetString(result.Buffer);
if (receivedSecret == secret)
{
byte[] okBytes = BitConverter.GetBytes(true);
await _serverUdpClient.SendAsync(okBytes, okBytes.Length, result.RemoteEndPoint);
}
}
}
#endregion
#region Client
/// <summary>
/// Makes this <see cref="NetworkDiscovery"/> component start searching for servers.
/// </summary>
public void StartSearchingForServers()
{
// if (InstanceFinder.IsServer)
// {
// if (NetworkManager.StaticCanLog(LoggingType.Warning)) Debug.LogWarning("Unable to start searching for servers. Server is active.", this);
//
// return;
// }
if (InstanceFinder.IsClient)
{
if (NetworkManager.StaticCanLog(LoggingType.Warning)) Debug.LogWarning("Unable to start searching for servers. Client is active.", this);
return;
}
if (_clientUdpClient != null)
{
if (NetworkManager.StaticCanLog(LoggingType.Common)) Debug.Log("Already searching for servers.", this);
return;
}
_clientUdpClient = new UdpClient()
{
EnableBroadcast = true,
MulticastLoopback = false,
};
Task.Run(SearchForServersAsync);
if (NetworkManager.StaticCanLog(LoggingType.Common)) Debug.Log("Started searching for servers.", this);
}
/// <summary>
/// Makes this <see cref="NetworkDiscovery"/> component <i>immediately</i> stop searching for servers.
/// </summary>
public void StopSearchingForServers()
{
if (_clientUdpClient == null) return;
_clientUdpClient.Close();
_clientUdpClient = null;
if (NetworkManager.StaticCanLog(LoggingType.Common)) Debug.Log("Stopped searching for servers.", this);
}
private async void SearchForServersAsync()
{
byte[] secretBytes = Encoding.UTF8.GetBytes(secret);
IPEndPoint endPoint = new IPEndPoint(IPAddress.Broadcast, port);
while (_clientUdpClient != null)
{
await Task.Delay(TimeSpan.FromSeconds(discoveryInterval));
await _clientUdpClient.SendAsync(secretBytes, secretBytes.Length, endPoint);
UdpReceiveResult result = await _clientUdpClient.ReceiveAsync();
if (BitConverter.ToBoolean(result.Buffer, 0))
{
ServerFoundCallback?.Invoke(result.RemoteEndPoint);
StopSearchingForServers();
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,117 @@
using System.Collections.Generic;
using System.Net;
using UnityEngine;
namespace FishNet.Discovery
{
public sealed class NetworkDiscoveryHUD : MonoBehaviour
{
[SerializeField]
private NetworkDiscovery networkDiscovery;
private Camera _camera;
private readonly List<IPEndPoint> _endPoints = new List<IPEndPoint>();
private Vector2 _serversListScrollVector;
private bool _useVR;
private void Start()
{
if (networkDiscovery == null) networkDiscovery = FindObjectOfType<NetworkDiscovery>();
_camera = GetComponentInChildren<Camera>();
_useVR = PlayerPrefs.GetInt("UseVR", 0) == 1;
networkDiscovery.ServerFoundCallback += (endPoint) =>
{
if (!_endPoints.Contains(endPoint)) _endPoints.Add(endPoint);
};
}
private void OnGUI()
{
GUILayoutOption buttonHeight = GUILayout.Height(30.0f);
using (new GUILayout.AreaScope(new Rect(Screen.width - 240.0f - 10.0f, 10.0f, 240.0f, Screen.height - 20.0f)))
{
GUILayout.Box("Settings");
using (new GUILayout.HorizontalScope())
{
bool useVRNew = GUILayout.Toggle(_useVR, "Use VR");
if (useVRNew != _useVR)
{
_useVR = useVRNew;
PlayerPrefs.SetInt("UseVR", _useVR ? 1 : 0);
Debug.Log($"UseVR set to {_useVR}");
}
}
GUILayout.Box("Server");
using (new GUILayout.HorizontalScope())
{
if (GUILayout.Button("Start", buttonHeight)) InstanceFinder.ServerManager.StartConnection();
if (GUILayout.Button("Stop", buttonHeight)) InstanceFinder.ServerManager.StopConnection(true);
}
GUILayout.Box("Advertising");
using (new GUILayout.HorizontalScope())
{
if (networkDiscovery.IsAdvertising)
{
if (GUILayout.Button("Stop", buttonHeight)) networkDiscovery.StopAdvertisingServer();
}
else
{
if (GUILayout.Button("Start", buttonHeight)) networkDiscovery.StartAdvertisingServer();
}
}
GUILayout.Box("Searching");
using (new GUILayout.HorizontalScope())
{
if (networkDiscovery.IsSearching)
{
if (GUILayout.Button("Stop", buttonHeight)) networkDiscovery.StopSearchingForServers();
}
else
{
if (GUILayout.Button("Start", buttonHeight)) networkDiscovery.StartSearchingForServers();
}
}
if (_endPoints.Count > 0)
{
GUILayout.Box("Servers");
using (new GUILayout.ScrollViewScope(_serversListScrollVector))
{
for (int i = 0; i < _endPoints.Count; i++)
{
string ipAddress = _endPoints[i].Address.ToString();
if (GUILayout.Button(ipAddress))
{
//networkDiscovery.StopAdvertisingServer();
networkDiscovery.StopSearchingForServers();
_camera.enabled = false;
InstanceFinder.ClientManager.StartConnection(ipAddress);
}
}
}
}
}
}
}
}

View File

@@ -0,0 +1,48 @@
# Fish-Networking-Discovery
A very simple LAN network discovery component for Fish-Networking ([Asset Store](https://assetstore.unity.com/packages/tools/network/fish-net-networking-evolved-207815) | [GitHub](https://github.com/FirstGearGames/FishNet))
### Getting Started (GUI)
1. Download the code in this repo as a zip
2. Extract the code inside your project folder **(FISH-NETWORKING MUST BE ALREADY INSTALLED)**
3. Create an empty game object
4. Add a `NetworkManager` component to the game object you just created
5. Add a `NetworkDiscovery` component to the game object you just created
6. Set the `secret`, `port`, and `discoveryInterval` fields
7. Add a `NetworkDiscoveryHUD` component
8. Enter play mode
- If you want to begin advertising a server
1. Press "Start" under the "Server" group
2. Press "Start" under the "Advertising" group
- If you want to stop advertising a server
- Press "Stop" under the "Advertising" group
- If you want to begin searching for servers
- Press "Start" under the "Searching" group
- If you want to stop searching for servers
- Press "Stop" under the "Searching" group
### Getting Started (Code)
1. Download the code in this repo as a zip
2. Extract the code inside your project folder **(FISH-NETWORKING MUST BE ALREADY INSTALLED)**
3. Create an empty game object
4. Add a `NetworkManager` component to the game object you just created
5. Add a `NetworkDiscovery` component to the game object you just created
6. Set the `secret`, `port`, and `discoveryInterval` fields
7. Enter play mode
- If you want begin advertising a server
1. Call `InstanceFinder.ServerManager.StartConnection()`
2. Call `FindObjectOfType<NetworkDiscovery>().StartAdvertisingServer()`
- If you want to stop advertising a server
- Call `FindObjectOfType<NetworkDiscovery>().StopAdvertisingServer()`
- If you want to start searching for servers
- Call `FindObjectOfType<NetworkDiscovery>().StartSearchingForServers()`
- If you want to stop seaching for servers
- Call `FindObjectOfType<NetworkDiscovery>().StopSearchingForServers()`
### Planned Features
- [x] Automatically start/stop advertising server
- [ ] Automatically remove servers that are no longer alive
- [ ] Introduce Unity coroutines for all `NetworkDiscovery` methods