init
This commit is contained in:
151
Assets/TcgEngine/Scripts/Network/Authenticator.cs
Normal file
151
Assets/TcgEngine/Scripts/Network/Authenticator.cs
Normal file
@@ -0,0 +1,151 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TcgEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for all Authenticators, must be inherited
|
||||
/// </summary>
|
||||
|
||||
public abstract class Authenticator
|
||||
{
|
||||
protected string user_id = null;
|
||||
protected string username = null;
|
||||
protected bool logged_in = false;
|
||||
protected bool inited = false;
|
||||
|
||||
public virtual async Task Initialize()
|
||||
{
|
||||
inited = true;
|
||||
await Task.Yield(); //Do nothing
|
||||
}
|
||||
|
||||
public virtual async Task<bool> Login(string username)
|
||||
{
|
||||
await Task.Yield(); //Do nothing
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual async Task<bool> Login(string username, string token)
|
||||
{
|
||||
return await Login(username); //Some authenticator dont define this function
|
||||
}
|
||||
|
||||
public virtual async Task<bool> RefreshLogin()
|
||||
{
|
||||
return await Login(username); //Same as Login if not defined
|
||||
}
|
||||
|
||||
//Bypass login system by just assigning your own values, for testing
|
||||
public virtual void LoginTest(string username)
|
||||
{
|
||||
this.user_id = username;
|
||||
this.username = username;
|
||||
logged_in = true;
|
||||
}
|
||||
|
||||
public virtual async Task<bool> Register(string username, string email, string token)
|
||||
{
|
||||
return await Login(username, token); //Some authenticator dont define this function
|
||||
}
|
||||
|
||||
public virtual async Task<UserData> LoadUserData()
|
||||
{
|
||||
await Task.Yield(); //Do nothing
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual async Task<bool> SaveUserData()
|
||||
{
|
||||
await Task.Yield(); //Do nothing
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual void Logout()
|
||||
{
|
||||
logged_in = false;
|
||||
user_id = null;
|
||||
username = null;
|
||||
}
|
||||
|
||||
public virtual bool IsInited()
|
||||
{
|
||||
return inited;
|
||||
}
|
||||
|
||||
public virtual bool IsConnected()
|
||||
{
|
||||
return IsSignedIn() && !IsExpired();
|
||||
}
|
||||
|
||||
public virtual bool IsSignedIn()
|
||||
{
|
||||
return logged_in; //IsSignedIn will still be true if the login expires
|
||||
}
|
||||
|
||||
public virtual bool IsExpired()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual string GetUserId()
|
||||
{
|
||||
return user_id;
|
||||
}
|
||||
|
||||
public virtual string GetUsername()
|
||||
{
|
||||
return username;
|
||||
}
|
||||
|
||||
public virtual int GetPermission()
|
||||
{
|
||||
return logged_in ? 1 : 0;
|
||||
}
|
||||
|
||||
public virtual UserData GetUserData()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual string GetError()
|
||||
{
|
||||
return ""; //Should return the latest error
|
||||
}
|
||||
|
||||
public bool IsTest()
|
||||
{
|
||||
return NetworkData.Get().auth_type == AuthenticatorType.LocalSave;
|
||||
}
|
||||
|
||||
public bool IsApi()
|
||||
{
|
||||
return NetworkData.Get().auth_type == AuthenticatorType.Api;
|
||||
}
|
||||
|
||||
public string UserID{ get{ return GetUserId(); }}
|
||||
public string Username{ get { return GetUsername(); } }
|
||||
public UserData UserData{ get { return GetUserData(); } }
|
||||
|
||||
public static Authenticator Create(AuthenticatorType type)
|
||||
{
|
||||
if (type == AuthenticatorType.Api)
|
||||
return new AuthenticatorApi();
|
||||
else
|
||||
return new AuthenticatorLocal();
|
||||
}
|
||||
|
||||
public static Authenticator Get()
|
||||
{
|
||||
return TcgNetwork.Get().Auth; //Access authenticator
|
||||
}
|
||||
}
|
||||
|
||||
public enum AuthenticatorType
|
||||
{
|
||||
LocalSave = 0, //Test Mode, Fake login for quick testing without the need to login each time
|
||||
Api = 10, //Actual online login
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/Network/Authenticator.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/Network/Authenticator.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7a56e07537e90ef46b7f66b6f65dd361
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
105
Assets/TcgEngine/Scripts/Network/AuthenticatorApi.cs
Normal file
105
Assets/TcgEngine/Scripts/Network/AuthenticatorApi.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TcgEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// This authenticator require external UserLogin API asset
|
||||
/// It works with an actual web API and database containing all user info
|
||||
/// </summary>
|
||||
|
||||
public class AuthenticatorApi : Authenticator
|
||||
{
|
||||
private int permission = 0;
|
||||
|
||||
public override async Task Initialize()
|
||||
{
|
||||
await base.Initialize();
|
||||
}
|
||||
|
||||
public override async Task<bool> Login(string username, string password)
|
||||
{
|
||||
LoginResponse res = await Client.Login(username, password);
|
||||
if (res.success)
|
||||
{
|
||||
this.logged_in = true;
|
||||
this.user_id = res.id;
|
||||
this.username = res.username;
|
||||
permission = res.permission_level;
|
||||
}
|
||||
return res.success;
|
||||
}
|
||||
|
||||
public override async Task<bool> RefreshLogin()
|
||||
{
|
||||
LoginResponse res = await Client.RefreshLogin();
|
||||
if (res.success)
|
||||
{
|
||||
this.logged_in = true;
|
||||
this.user_id = res.id;
|
||||
this.username = res.username;
|
||||
}
|
||||
return res.success;
|
||||
}
|
||||
|
||||
public override async Task<bool> Register(string username, string email, string password)
|
||||
{
|
||||
RegisterResponse res = await Client.Register(username, email, password);
|
||||
|
||||
if (res.success)
|
||||
await Login(username, password);
|
||||
|
||||
return res.success;
|
||||
}
|
||||
|
||||
public override async Task<UserData> LoadUserData()
|
||||
{
|
||||
UserData res = await Client.LoadUserData();
|
||||
return res;
|
||||
}
|
||||
|
||||
public override async Task<bool> SaveUserData()
|
||||
{
|
||||
//Do nothing, saved on each api request, no need to save to disk
|
||||
await Task.Yield();
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Logout()
|
||||
{
|
||||
base.Logout();
|
||||
Client.Logout();
|
||||
permission = 0;
|
||||
}
|
||||
|
||||
public override UserData GetUserData()
|
||||
{
|
||||
return Client.UserData;
|
||||
}
|
||||
|
||||
public override bool IsSignedIn()
|
||||
{
|
||||
return Client.IsLoggedIn();
|
||||
}
|
||||
|
||||
public override bool IsExpired()
|
||||
{
|
||||
return Client.IsExpired();
|
||||
}
|
||||
|
||||
public override int GetPermission()
|
||||
{
|
||||
return permission;
|
||||
}
|
||||
|
||||
public override string GetError()
|
||||
{
|
||||
return Client.GetLastError();
|
||||
}
|
||||
|
||||
public ApiClient Client { get { return ApiClient.Get(); } }
|
||||
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/Network/AuthenticatorApi.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/Network/AuthenticatorApi.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0522f2da9e4192e4cb5d83f4dfb2e2b0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
84
Assets/TcgEngine/Scripts/Network/AuthenticatorLocal.cs
Normal file
84
Assets/TcgEngine/Scripts/Network/AuthenticatorLocal.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TcgEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// Test authenticator just generates a random ID to use as user id
|
||||
/// This is very useful to test the game in multiplayer without needing to login each time
|
||||
/// Unity Services features won't work in test mode (Relay, Cloud Saves...)
|
||||
/// Use Anonymous mode to test those features (after connecting your project ID in services window)
|
||||
/// </summary>
|
||||
|
||||
public class AuthenticatorLocal : Authenticator
|
||||
{
|
||||
private UserData udata = null;
|
||||
|
||||
public override async Task<bool> Login(string username)
|
||||
{
|
||||
this.user_id = username; //User username as ID for save file consistency when testing
|
||||
this.username = username;
|
||||
logged_in = true;
|
||||
await Task.Yield(); //Do nothing
|
||||
PlayerPrefs.SetString("tcg_user", username); //Save last user
|
||||
return true;
|
||||
}
|
||||
|
||||
public override async Task<bool> RefreshLogin()
|
||||
{
|
||||
string username = PlayerPrefs.GetString("tcg_user", "");
|
||||
if (!string.IsNullOrEmpty(username))
|
||||
{
|
||||
bool success = await Login(username);
|
||||
return success;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override async Task<UserData> LoadUserData()
|
||||
{
|
||||
string user = PlayerPrefs.GetString("tcg_user", "");
|
||||
string file = username + ".user";
|
||||
if (!string.IsNullOrEmpty(user) && SaveTool.DoesFileExist(file))
|
||||
{
|
||||
udata = SaveTool.LoadFile<UserData>(file);
|
||||
}
|
||||
|
||||
if(udata == null)
|
||||
{
|
||||
udata = new UserData();
|
||||
udata.username = username;
|
||||
udata.id = username;
|
||||
}
|
||||
|
||||
await Task.Yield(); //Do nothing
|
||||
return udata;
|
||||
}
|
||||
|
||||
public override async Task<bool> SaveUserData()
|
||||
{
|
||||
if (udata != null && SaveTool.IsValidFilename(username))
|
||||
{
|
||||
string file = username + ".user";
|
||||
SaveTool.SaveFile<UserData>(file, udata);
|
||||
await Task.Yield(); //Do nothing
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Logout()
|
||||
{
|
||||
base.Logout();
|
||||
udata = null;
|
||||
PlayerPrefs.DeleteKey("tcg_user");
|
||||
}
|
||||
|
||||
public override UserData GetUserData()
|
||||
{
|
||||
return udata;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/Network/AuthenticatorLocal.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/Network/AuthenticatorLocal.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4def3c2352754d840b1f4c9c558100b4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
38
Assets/TcgEngine/Scripts/Network/NetworkData.cs
Normal file
38
Assets/TcgEngine/Scripts/Network/NetworkData.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TcgEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// Main config file for all network-related things
|
||||
/// Server API password is not in this file (and is in the Server scene instead) to prevent exposing it to client build
|
||||
/// </summary>
|
||||
|
||||
[CreateAssetMenu(fileName = "NetworkData", menuName = "TcgEngine/NetworkData", order = 0)]
|
||||
public class NetworkData : ScriptableObject
|
||||
{
|
||||
[Header("Game Server")]
|
||||
public string url; //Url of your Game Server
|
||||
public ushort port; //Port to connect/listen on your game server
|
||||
|
||||
[Header("API")]
|
||||
public string api_url; //Url of your Nodejs API (can be same as Game Server)
|
||||
public bool api_https; //Http or Https ? Http will use port 80, https will use port 443
|
||||
|
||||
[Header("Settings")]
|
||||
public SoloType solo_type; //Wether to use Netcode or not in Solo mode (multiplayer always use netcode), using Netcode means more consistency between the 2 modes
|
||||
public AuthenticatorType auth_type; //Test Mode (local mode) or API mode
|
||||
|
||||
public static NetworkData Get()
|
||||
{
|
||||
return TcgNetwork.Get().data;
|
||||
}
|
||||
}
|
||||
|
||||
public enum SoloType
|
||||
{
|
||||
UseNetcode = 0, //Use Netcode network messages in solo to have more similar behavior on both multiplayer and solo, Recommended for consistency between multi/solo
|
||||
Offline = 10 //Make solo totally offline (no netcode) but may behave differently than multiplayer, required for WebGL since StartHost don't work on webgl.
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/Network/NetworkData.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/Network/NetworkData.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 70dc9fcaed7d5274a8381edb4e206a92
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
405
Assets/TcgEngine/Scripts/Network/NetworkMessaging.cs
Normal file
405
Assets/TcgEngine/Scripts/Network/NetworkMessaging.cs
Normal file
@@ -0,0 +1,405 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Collections;
|
||||
using Unity.Netcode;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TcgEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for sending and receiving network messages
|
||||
/// </summary>
|
||||
|
||||
public class NetworkMessaging
|
||||
{
|
||||
private TcgNetwork network;
|
||||
|
||||
private Dictionary<string, System.Action<ulong, FastBufferReader>> msg_dict = new Dictionary<string, System.Action<ulong, FastBufferReader>>();
|
||||
|
||||
public NetworkMessaging(TcgNetwork network)
|
||||
{
|
||||
this.network = network;
|
||||
network.onConnect += OnConnect;
|
||||
}
|
||||
|
||||
private void OnConnect()
|
||||
{
|
||||
foreach (KeyValuePair<string, System.Action<ulong, FastBufferReader>> pair in msg_dict)
|
||||
{
|
||||
RegisterNetMsg(pair.Key, pair.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public void ListenMsg(string type, System.Action<ulong, FastBufferReader> callback)
|
||||
{
|
||||
msg_dict[type] = callback;
|
||||
RegisterNetMsg(type, callback);
|
||||
}
|
||||
|
||||
public void UnListenMsg(string type)
|
||||
{
|
||||
msg_dict.Remove(type);
|
||||
|
||||
if (network.NetworkManager.CustomMessagingManager != null)
|
||||
network.NetworkManager.CustomMessagingManager.UnregisterNamedMessageHandler(type);
|
||||
}
|
||||
|
||||
private void RegisterNetMsg(string type, System.Action<ulong, FastBufferReader> callback)
|
||||
{
|
||||
if (IsOnline)
|
||||
{
|
||||
network.NetworkManager.CustomMessagingManager.RegisterNamedMessageHandler(type, (ulong client_id, FastBufferReader reader) =>
|
||||
{
|
||||
ReceiveNetMessage(type, client_id, reader);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void ReceiveNetMessage(string type, ulong client_id, FastBufferReader reader)
|
||||
{
|
||||
bool valid = msg_dict.TryGetValue(type, out System.Action<ulong, FastBufferReader> callback);
|
||||
if (valid && IsOnline)
|
||||
{
|
||||
callback(client_id, reader);
|
||||
}
|
||||
}
|
||||
|
||||
//--------- Send Single ----------
|
||||
|
||||
public void SendEmpty(string type, ulong target, NetworkDelivery delivery)
|
||||
{
|
||||
FastBufferWriter writer = new FastBufferWriter(0, Allocator.Temp);
|
||||
Send(type, target, writer, delivery);
|
||||
writer.Dispose();
|
||||
}
|
||||
|
||||
public void SendBytes(string type, ulong target, byte[] msg, NetworkDelivery delivery)
|
||||
{
|
||||
FastBufferWriter writer = new FastBufferWriter(msg.Length, Allocator.Temp);
|
||||
writer.WriteBytesSafe(msg, msg.Length);
|
||||
Send(type, target, writer, delivery);
|
||||
writer.Dispose();
|
||||
}
|
||||
|
||||
public void SendString(string type, ulong target, string msg, NetworkDelivery delivery)
|
||||
{
|
||||
FastBufferWriter writer = new FastBufferWriter(msg.Length, Allocator.Temp, TcgNetwork.MsgSizeMax);
|
||||
writer.WriteValueSafe(msg);
|
||||
Send(type, target, writer, delivery);
|
||||
writer.Dispose();
|
||||
}
|
||||
|
||||
public void SendInt(string type, ulong target, int data, NetworkDelivery delivery)
|
||||
{
|
||||
FastBufferWriter writer = new FastBufferWriter(4, Allocator.Temp);
|
||||
writer.WriteValueSafe(data);
|
||||
Send(type, target, writer, delivery);
|
||||
writer.Dispose();
|
||||
}
|
||||
|
||||
public void SendUInt64(string type, ulong target, ulong data, NetworkDelivery delivery)
|
||||
{
|
||||
FastBufferWriter writer = new FastBufferWriter(8, Allocator.Temp);
|
||||
writer.WriteValueSafe(data);
|
||||
Send(type, target, writer, delivery);
|
||||
writer.Dispose();
|
||||
}
|
||||
|
||||
public void SendFloat(string type, ulong target, float data, NetworkDelivery delivery)
|
||||
{
|
||||
FastBufferWriter writer = new FastBufferWriter(4, Allocator.Temp);
|
||||
writer.WriteValueSafe(data);
|
||||
Send(type, target, writer, delivery);
|
||||
writer.Dispose();
|
||||
}
|
||||
|
||||
public void SendObject<T>(string type, ulong target, T data, NetworkDelivery delivery) where T : INetworkSerializable
|
||||
{
|
||||
FastBufferWriter writer = new FastBufferWriter(256, Allocator.Temp, TcgNetwork.MsgSizeMax);
|
||||
writer.WriteNetworkSerializable(data);
|
||||
Send(type, target, writer, delivery);
|
||||
writer.Dispose();
|
||||
}
|
||||
|
||||
//--------- Send Multi ----------
|
||||
|
||||
public void SendEmpty(string type, IReadOnlyList<ulong> targets, NetworkDelivery delivery)
|
||||
{
|
||||
if (IsServer)
|
||||
{
|
||||
FastBufferWriter writer = new FastBufferWriter(0, Allocator.Temp);
|
||||
Send(type, targets, writer, delivery);
|
||||
writer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void SendBytes(string type, IReadOnlyList<ulong> targets, byte[] msg, NetworkDelivery delivery)
|
||||
{
|
||||
if (IsServer)
|
||||
{
|
||||
FastBufferWriter writer = new FastBufferWriter(msg.Length, Allocator.Temp);
|
||||
writer.WriteBytesSafe(msg, msg.Length);
|
||||
Send(type, targets, writer, delivery);
|
||||
writer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void SendString(string type, IReadOnlyList<ulong> targets, string msg, NetworkDelivery delivery)
|
||||
{
|
||||
if (IsServer)
|
||||
{
|
||||
FastBufferWriter writer = new FastBufferWriter(msg.Length, Allocator.Temp, TcgNetwork.MsgSizeMax);
|
||||
writer.WriteValueSafe(msg);
|
||||
Send(type, targets, writer, delivery);
|
||||
writer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void SendInt(string type, IReadOnlyList<ulong> targets, int data, NetworkDelivery delivery)
|
||||
{
|
||||
if (IsServer)
|
||||
{
|
||||
FastBufferWriter writer = new FastBufferWriter(4, Allocator.Temp);
|
||||
writer.WriteValueSafe(data);
|
||||
Send(type, targets, writer, delivery);
|
||||
writer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void SendUInt64(string type, IReadOnlyList<ulong> targets, ulong data, NetworkDelivery delivery)
|
||||
{
|
||||
if (IsServer)
|
||||
{
|
||||
FastBufferWriter writer = new FastBufferWriter(8, Allocator.Temp);
|
||||
writer.WriteValueSafe(data);
|
||||
Send(type, targets, writer, delivery);
|
||||
writer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void SendFloat(string type, IReadOnlyList<ulong> targets, float data, NetworkDelivery delivery)
|
||||
{
|
||||
if (IsServer)
|
||||
{
|
||||
FastBufferWriter writer = new FastBufferWriter(4, Allocator.Temp);
|
||||
writer.WriteValueSafe(data);
|
||||
Send(type, targets, writer, delivery);
|
||||
writer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void SendObject<T>(string type, IReadOnlyList<ulong> targets, T data, NetworkDelivery delivery) where T : INetworkSerializable
|
||||
{
|
||||
if (IsServer)
|
||||
{
|
||||
FastBufferWriter writer = new FastBufferWriter(256, Allocator.Temp, TcgNetwork.MsgSizeMax);
|
||||
writer.WriteNetworkSerializable(data);
|
||||
Send(type, targets, writer, delivery);
|
||||
writer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
//--------- Send All ----------
|
||||
|
||||
public void SendEmptyAll(string type, NetworkDelivery delivery)
|
||||
{
|
||||
if (IsServer)
|
||||
{
|
||||
FastBufferWriter writer = new FastBufferWriter(0, Allocator.Temp);
|
||||
SendAll(type, writer, delivery);
|
||||
writer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void SendStringAll(string type, string msg, NetworkDelivery delivery)
|
||||
{
|
||||
if (IsServer)
|
||||
{
|
||||
FastBufferWriter writer = new FastBufferWriter(msg.Length, Allocator.Temp, TcgNetwork.MsgSizeMax);
|
||||
writer.WriteValueSafe(msg);
|
||||
SendAll(type, writer, delivery);
|
||||
writer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void SendIntAll(string type, int data, NetworkDelivery delivery)
|
||||
{
|
||||
if (IsServer)
|
||||
{
|
||||
FastBufferWriter writer = new FastBufferWriter(4, Allocator.Temp);
|
||||
writer.WriteValueSafe(data);
|
||||
SendAll(type, writer, delivery);
|
||||
writer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void SendUInt64All(string type, ulong data, NetworkDelivery delivery)
|
||||
{
|
||||
if (IsServer)
|
||||
{
|
||||
FastBufferWriter writer = new FastBufferWriter(8, Allocator.Temp);
|
||||
writer.WriteValueSafe(data);
|
||||
SendAll(type, writer, delivery);
|
||||
writer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void SendFloatAll(string type, float data, NetworkDelivery delivery)
|
||||
{
|
||||
if (IsServer)
|
||||
{
|
||||
FastBufferWriter writer = new FastBufferWriter(4, Allocator.Temp);
|
||||
writer.WriteValueSafe(data);
|
||||
SendAll(type, writer, delivery);
|
||||
writer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void SendBytesAll(string type, byte[] msg, NetworkDelivery delivery)
|
||||
{
|
||||
if (IsServer)
|
||||
{
|
||||
FastBufferWriter writer = new FastBufferWriter(msg.Length, Allocator.Temp);
|
||||
writer.WriteBytesSafe(msg, msg.Length);
|
||||
SendAll(type, writer, delivery);
|
||||
writer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void SendObjectAll<T>(string type, T data, NetworkDelivery delivery) where T : INetworkSerializable
|
||||
{
|
||||
if (IsServer)
|
||||
{
|
||||
FastBufferWriter writer = new FastBufferWriter(256, Allocator.Temp, TcgNetwork.MsgSizeMax);
|
||||
writer.WriteNetworkSerializable(data);
|
||||
SendAll(type, writer, delivery);
|
||||
writer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
//-------- Generic Send ----------
|
||||
|
||||
public void Send(string type, ulong target, FastBufferWriter writer, NetworkDelivery delivery)
|
||||
{
|
||||
if (IsOnline)
|
||||
SendOnline(type, target, writer, delivery);
|
||||
else if(target == ClientID)
|
||||
SendOffline(type, writer);
|
||||
}
|
||||
|
||||
public void Send(string type, IReadOnlyList<ulong> targets, FastBufferWriter writer, NetworkDelivery delivery)
|
||||
{
|
||||
if (IsOnline)
|
||||
SendOnline(type, targets, writer, delivery);
|
||||
else if (Contains(targets, ClientID))
|
||||
SendOffline(type, writer);
|
||||
}
|
||||
|
||||
public void SendAll(string type, FastBufferWriter writer, NetworkDelivery delivery)
|
||||
{
|
||||
Send(type, ClientList, writer, delivery);
|
||||
}
|
||||
|
||||
private void SendOnline(string type, ulong target, FastBufferWriter writer, NetworkDelivery delivery)
|
||||
{
|
||||
network.NetworkManager.CustomMessagingManager.SendNamedMessage(type, target, writer, delivery);
|
||||
}
|
||||
|
||||
private void SendOnline(string type, IReadOnlyList<ulong> targets, FastBufferWriter writer, NetworkDelivery delivery)
|
||||
{
|
||||
network.NetworkManager.CustomMessagingManager.SendNamedMessage(type, targets, writer, delivery);
|
||||
}
|
||||
|
||||
//Just copy the message from writer to reader locally and call the callback immediately
|
||||
private void SendOffline(string type, FastBufferWriter writer)
|
||||
{
|
||||
bool found = msg_dict.TryGetValue(type, out System.Action<ulong, FastBufferReader> callback);
|
||||
if (found)
|
||||
{
|
||||
FastBufferReader reader = new FastBufferReader(writer, Allocator.Temp);
|
||||
callback?.Invoke(ClientID, reader);
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
//--------- Forward msgs ----------
|
||||
|
||||
//Forward a client message to one client
|
||||
//Make sure you finished reading the reader before forwarding
|
||||
public void Forward(string type, ulong target, FastBufferReader reader, NetworkDelivery delivery)
|
||||
{
|
||||
if (IsServer && IsOnline)
|
||||
{
|
||||
reader.Seek(0); //Reset reader
|
||||
reader.ReadValueSafe(out ulong header); //Ignore header
|
||||
byte[] bytes = new byte[reader.Length - reader.Position];
|
||||
reader.ReadBytesSafe(ref bytes, reader.Length - reader.Position);
|
||||
FastBufferWriter writer = new FastBufferWriter(bytes.Length, Allocator.Temp);
|
||||
writer.WriteBytesSafe(bytes, bytes.Length);
|
||||
network.NetworkManager.CustomMessagingManager.SendNamedMessage(type, target, writer, delivery);
|
||||
writer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
//Forward a client message to all target clients
|
||||
//Make sure you finished reading the reader before forwarding
|
||||
public void Forward(string type, IReadOnlyList<ulong> targets, FastBufferReader reader, NetworkDelivery delivery)
|
||||
{
|
||||
if (IsServer && IsOnline)
|
||||
{
|
||||
reader.Seek(0); //Reset reader
|
||||
reader.ReadValueSafe(out ulong header); //Ignore header
|
||||
byte[] bytes = new byte[reader.Length - reader.Position];
|
||||
reader.ReadBytesSafe(ref bytes, reader.Length - reader.Position);
|
||||
FastBufferWriter writer = new FastBufferWriter(bytes.Length, Allocator.Temp);
|
||||
writer.WriteBytesSafe(bytes, bytes.Length);
|
||||
network.NetworkManager.CustomMessagingManager.SendNamedMessage(type, targets, writer, delivery);
|
||||
writer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
//Forward a client message to all other clients (other than the source)
|
||||
//Make sure you finished reading the reader before forwarding
|
||||
public void ForwardAll(string type, ulong source_client, FastBufferReader reader, NetworkDelivery delivery)
|
||||
{
|
||||
if (IsServer && IsOnline)
|
||||
{
|
||||
reader.Seek(0); //Reset reader
|
||||
reader.ReadValueSafe(out ulong header); //Ignore header
|
||||
byte[] bytes = new byte[reader.Length - reader.Position];
|
||||
reader.ReadBytesSafe(ref bytes, reader.Length - reader.Position);
|
||||
FastBufferWriter writer = new FastBufferWriter(bytes.Length, Allocator.Temp);
|
||||
writer.WriteBytesSafe(bytes, bytes.Length);
|
||||
|
||||
foreach (ulong client in ClientList)
|
||||
{
|
||||
if(client != source_client && client != ClientID)
|
||||
network.NetworkManager.CustomMessagingManager.SendNamedMessage(type, client, writer, delivery);
|
||||
}
|
||||
writer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private bool Contains(IReadOnlyList<ulong> list, ulong client_id)
|
||||
{
|
||||
foreach (ulong cid in list)
|
||||
{
|
||||
if (cid == client_id)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public IReadOnlyList<ulong> ClientList { get { return network.GetClientsIds(); } }
|
||||
public bool IsOnline { get { return network.IsOnline; } }
|
||||
public bool IsServer { get { return network.IsServer; } }
|
||||
public ulong ServerID { get { return network.ServerID; } }
|
||||
public ulong ClientID { get { return network.ClientID; } }
|
||||
|
||||
|
||||
public static NetworkMessaging Get()
|
||||
{
|
||||
return TcgNetwork.Get().Messaging;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/Network/NetworkMessaging.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/Network/NetworkMessaging.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d92360b2bb9a0be4daa5a012f0b9b63c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
366
Assets/TcgEngine/Scripts/Network/NetworkMsg.cs
Normal file
366
Assets/TcgEngine/Scripts/Network/NetworkMsg.cs
Normal file
@@ -0,0 +1,366 @@
|
||||
|
||||
using Unity.Netcode;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace TcgEngine
|
||||
{
|
||||
//-------- Connection --------
|
||||
|
||||
public class MsgPlayerConnect : INetworkSerializable
|
||||
{
|
||||
public string user_id;
|
||||
public string username;
|
||||
public string game_uid;
|
||||
public int nb_players;
|
||||
public bool observer; //join as observer
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref user_id);
|
||||
serializer.SerializeValue(ref username);
|
||||
serializer.SerializeValue(ref game_uid);
|
||||
serializer.SerializeValue(ref nb_players);
|
||||
serializer.SerializeValue(ref observer);
|
||||
}
|
||||
}
|
||||
|
||||
public class MsgAfterConnected : INetworkSerializable
|
||||
{
|
||||
public bool success;
|
||||
public int player_id;
|
||||
public Game game_data;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref success);
|
||||
serializer.SerializeValue(ref player_id);
|
||||
|
||||
if (serializer.IsReader)
|
||||
{
|
||||
int size = 0;
|
||||
serializer.SerializeValue(ref size);
|
||||
if (size > 0)
|
||||
{
|
||||
byte[] bytes = new byte[size];
|
||||
serializer.SerializeValue(ref bytes);
|
||||
game_data = NetworkTool.Deserialize<Game>(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
if (serializer.IsWriter)
|
||||
{
|
||||
byte[] bytes = NetworkTool.Serialize(game_data);
|
||||
int size = bytes.Length;
|
||||
serializer.SerializeValue(ref size);
|
||||
if(size > 0)
|
||||
serializer.SerializeValue(ref bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------- Matchmaking --------
|
||||
|
||||
public class MsgMatchmaking : INetworkSerializable
|
||||
{
|
||||
public string user_id;
|
||||
public string username;
|
||||
public string group;
|
||||
public int players;
|
||||
public int elo;
|
||||
public bool refresh;
|
||||
public float time;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref user_id);
|
||||
serializer.SerializeValue(ref username);
|
||||
serializer.SerializeValue(ref group);
|
||||
serializer.SerializeValue(ref players);
|
||||
serializer.SerializeValue(ref elo);
|
||||
serializer.SerializeValue(ref refresh);
|
||||
serializer.SerializeValue(ref time);
|
||||
}
|
||||
}
|
||||
|
||||
public class MatchmakingResult : INetworkSerializable
|
||||
{
|
||||
public bool success;
|
||||
public int players;
|
||||
public string group;
|
||||
public string server_url;
|
||||
public string game_uid;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref success);
|
||||
serializer.SerializeValue(ref players);
|
||||
serializer.SerializeValue(ref group);
|
||||
serializer.SerializeValue(ref server_url);
|
||||
serializer.SerializeValue(ref game_uid);
|
||||
}
|
||||
}
|
||||
|
||||
public class MsgMatchmakingList : INetworkSerializable
|
||||
{
|
||||
public string username;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref username);
|
||||
}
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public struct MatchmakingListItem : INetworkSerializable
|
||||
{
|
||||
public string group;
|
||||
public string user_id;
|
||||
public string username;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref group);
|
||||
serializer.SerializeValue(ref user_id);
|
||||
serializer.SerializeValue(ref username);
|
||||
}
|
||||
}
|
||||
|
||||
public class MatchmakingList : INetworkSerializable
|
||||
{
|
||||
public MatchmakingListItem[] items;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
NetworkTool.NetSerializeArray(serializer, ref items);
|
||||
}
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class MatchListItem : INetworkSerializable
|
||||
{
|
||||
public string group;
|
||||
public string username;
|
||||
public string game_uid;
|
||||
public string game_url;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref group);
|
||||
serializer.SerializeValue(ref username);
|
||||
serializer.SerializeValue(ref game_uid);
|
||||
serializer.SerializeValue(ref game_url);
|
||||
}
|
||||
}
|
||||
|
||||
public class MatchList : INetworkSerializable
|
||||
{
|
||||
public MatchListItem[] items;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
NetworkTool.NetSerializeArray(serializer, ref items);
|
||||
}
|
||||
}
|
||||
|
||||
//-------- In Game --------
|
||||
|
||||
public class MsgPlayCard : INetworkSerializable
|
||||
{
|
||||
public string card_uid;
|
||||
public Slot slot;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref card_uid);
|
||||
serializer.SerializeNetworkSerializable(ref slot);
|
||||
}
|
||||
}
|
||||
|
||||
public class MsgCard : INetworkSerializable
|
||||
{
|
||||
public string card_uid;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref card_uid);
|
||||
}
|
||||
}
|
||||
|
||||
public class MsgCardValue : INetworkSerializable
|
||||
{
|
||||
public string card_uid;
|
||||
public int value;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref card_uid);
|
||||
serializer.SerializeValue(ref value);
|
||||
}
|
||||
}
|
||||
|
||||
public class MsgPlayer : INetworkSerializable
|
||||
{
|
||||
public int player_id;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref player_id);
|
||||
}
|
||||
}
|
||||
|
||||
public class MsgPlayerValue : INetworkSerializable
|
||||
{
|
||||
public int player_id;
|
||||
public int value;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref player_id);
|
||||
serializer.SerializeValue(ref value);
|
||||
}
|
||||
}
|
||||
|
||||
public class MsgAttack : INetworkSerializable
|
||||
{
|
||||
public string attacker_uid;
|
||||
public string target_uid;
|
||||
public int damage;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref attacker_uid);
|
||||
serializer.SerializeValue(ref target_uid);
|
||||
serializer.SerializeValue(ref damage);
|
||||
}
|
||||
}
|
||||
|
||||
public class MsgAttackPlayer : INetworkSerializable
|
||||
{
|
||||
public string attacker_uid;
|
||||
public int target_id;
|
||||
public int damage;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref attacker_uid);
|
||||
serializer.SerializeValue(ref target_id);
|
||||
serializer.SerializeValue(ref damage);
|
||||
}
|
||||
}
|
||||
|
||||
public class MsgCastAbility : INetworkSerializable
|
||||
{
|
||||
public string ability_id;
|
||||
public string caster_uid;
|
||||
public string target_uid;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref ability_id);
|
||||
serializer.SerializeValue(ref caster_uid);
|
||||
serializer.SerializeValue(ref target_uid);
|
||||
}
|
||||
}
|
||||
|
||||
public class MsgCastAbilityPlayer : INetworkSerializable
|
||||
{
|
||||
public string ability_id;
|
||||
public string caster_uid;
|
||||
public int target_id;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref ability_id);
|
||||
serializer.SerializeValue(ref caster_uid);
|
||||
serializer.SerializeValue(ref target_id);
|
||||
}
|
||||
}
|
||||
|
||||
public class MsgCastAbilitySlot : INetworkSerializable
|
||||
{
|
||||
public string ability_id;
|
||||
public string caster_uid;
|
||||
public Slot slot;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref ability_id);
|
||||
serializer.SerializeValue(ref caster_uid);
|
||||
serializer.SerializeNetworkSerializable(ref slot);
|
||||
}
|
||||
}
|
||||
|
||||
public class MsgSecret : INetworkSerializable
|
||||
{
|
||||
public string secret_uid;
|
||||
public string triggerer_uid;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref secret_uid);
|
||||
serializer.SerializeValue(ref triggerer_uid);
|
||||
}
|
||||
}
|
||||
|
||||
public class MsgMulligan : INetworkSerializable
|
||||
{
|
||||
public string[] cards;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
NetworkTool.NetSerializeArray(serializer, ref cards);
|
||||
}
|
||||
}
|
||||
|
||||
public class MsgInt : INetworkSerializable
|
||||
{
|
||||
public int value;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref value);
|
||||
}
|
||||
}
|
||||
|
||||
public class MsgChat : INetworkSerializable
|
||||
{
|
||||
public int player_id;
|
||||
public string msg;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref player_id);
|
||||
serializer.SerializeValue(ref msg);
|
||||
}
|
||||
}
|
||||
|
||||
public class MsgRefreshAll : INetworkSerializable
|
||||
{
|
||||
public Game game_data;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
if (serializer.IsReader)
|
||||
{
|
||||
int size = 0;
|
||||
serializer.SerializeValue(ref size);
|
||||
if (size > 0)
|
||||
{
|
||||
byte[] bytes = new byte[size];
|
||||
serializer.SerializeValue(ref bytes);
|
||||
game_data = NetworkTool.Deserialize<Game>(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
if (serializer.IsWriter)
|
||||
{
|
||||
byte[] bytes = NetworkTool.Serialize(game_data);
|
||||
int size = bytes.Length;
|
||||
serializer.SerializeValue(ref size);
|
||||
if (size > 0)
|
||||
serializer.SerializeValue(ref bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/Network/NetworkMsg.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/Network/NetworkMsg.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc2dfed09963fd54eafcfe01672fdb4b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
387
Assets/TcgEngine/Scripts/Network/TcgNetwork.cs
Normal file
387
Assets/TcgEngine/Scripts/Network/TcgNetwork.cs
Normal file
@@ -0,0 +1,387 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Collections;
|
||||
using Unity.Netcode;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace TcgEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// Main script handling network connection betweeen server and client
|
||||
/// It's one of the few scripts in this asset that needs to be on a DontDestroyOnLoad object
|
||||
/// </summary>
|
||||
|
||||
[DefaultExecutionOrder(-10)]
|
||||
[RequireComponent(typeof(NetworkManager))]
|
||||
[RequireComponent(typeof(TcgTransport))]
|
||||
public class TcgNetwork : MonoBehaviour
|
||||
{
|
||||
public NetworkData data;
|
||||
|
||||
//Server & Client events
|
||||
public UnityAction onTick; //Every network tick
|
||||
public UnityAction onConnect; //Event when self connect, happens before onReady, before sending any data
|
||||
public UnityAction onDisconnect; //Event when self disconnect
|
||||
|
||||
//Server only events
|
||||
public UnityAction<ulong> onClientJoin; //Server event when any client connect
|
||||
public UnityAction<ulong> onClientQuit; //Server event when any client disconnect
|
||||
public UnityAction<ulong> onClientReady; //Server event when any client become ready
|
||||
|
||||
public delegate bool ApprovalEvent(ulong client_id, ConnectionData connect_data);
|
||||
public ApprovalEvent checkApproval; //Additional approval validations for when a client connects
|
||||
|
||||
//---------
|
||||
|
||||
private NetworkManager network;
|
||||
private TcgTransport transport;
|
||||
private NetworkMessaging messaging;
|
||||
private Authenticator auth;
|
||||
private ConnectionData connection;
|
||||
|
||||
[System.NonSerialized]
|
||||
private static bool inited = false;
|
||||
private static TcgNetwork instance;
|
||||
|
||||
private const int msg_size = 1024 * 1024;
|
||||
private bool offline_mode = false;
|
||||
private bool connected = false;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (instance != null && instance != this)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return; //Manager already exists, destroy this one
|
||||
}
|
||||
|
||||
Init();
|
||||
DontDestroyOnLoad(gameObject);
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
if (!inited || transport == null)
|
||||
{
|
||||
instance = this;
|
||||
inited = true;
|
||||
network = GetComponent<NetworkManager>();
|
||||
transport = GetComponent<TcgTransport>();
|
||||
messaging = new NetworkMessaging(this);
|
||||
connection = new ConnectionData();
|
||||
transport.Init();
|
||||
|
||||
network.ConnectionApprovalCallback += ApprovalCheck;
|
||||
network.OnClientConnectedCallback += OnClientConnect;
|
||||
network.OnClientDisconnectCallback += OnClientDisconnect;
|
||||
|
||||
InitAuth();
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//Start a host (client + server)
|
||||
public void StartHost(ushort port)
|
||||
{
|
||||
Debug.Log("Host Server Port " + port);
|
||||
transport.SetServer(port);
|
||||
connection.user_id = auth.UserID;
|
||||
connection.username = auth.Username;
|
||||
network.NetworkConfig.ConnectionData = NetworkTool.NetSerialize(connection);
|
||||
offline_mode = false;
|
||||
network.StartHost();
|
||||
AfterConnected();
|
||||
}
|
||||
|
||||
//Start a dedicated server
|
||||
public void StartServer(ushort port)
|
||||
{
|
||||
Debug.Log("Start Server Port " + port);
|
||||
transport.SetServer(port);
|
||||
connection.user_id = "";
|
||||
connection.username = "";
|
||||
network.NetworkConfig.ConnectionData = NetworkTool.NetSerialize(connection);
|
||||
offline_mode = false;
|
||||
network.StartServer();
|
||||
AfterConnected();
|
||||
}
|
||||
|
||||
//If is_host is set to true, it means this player created the game on a dedicated server
|
||||
//so its still a client (not server) but is the one who selected game settings
|
||||
public void StartClient(string server_url, ushort port)
|
||||
{
|
||||
Debug.Log("Join Server: " + server_url + " " + port);
|
||||
transport.SetClient(server_url, port);
|
||||
connection.user_id = auth.UserID;
|
||||
connection.username = auth.Username;
|
||||
network.NetworkConfig.ConnectionData = NetworkTool.NetSerialize(connection);
|
||||
offline_mode = false;
|
||||
network.StartClient();
|
||||
}
|
||||
|
||||
//Start simulated host with all networking turned off
|
||||
public void StartHostOffline()
|
||||
{
|
||||
Debug.Log("Host Offline");
|
||||
Disconnect();
|
||||
offline_mode = true;
|
||||
AfterConnected();
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
if (!IsClient && !IsServer)
|
||||
return;
|
||||
|
||||
Debug.Log("Disconnect");
|
||||
network.Shutdown();
|
||||
AfterDisconnected();
|
||||
}
|
||||
|
||||
public void SetConnectionExtraData(byte[] bytes)
|
||||
{
|
||||
connection.extra = bytes;
|
||||
}
|
||||
|
||||
public void SetConnectionExtraData(string data)
|
||||
{
|
||||
connection.extra = NetworkTool.SerializeString(data);
|
||||
}
|
||||
|
||||
public void SetConnectionExtraData<T>(T data) where T : INetworkSerializable, new()
|
||||
{
|
||||
connection.extra = NetworkTool.NetSerialize(data);
|
||||
}
|
||||
|
||||
private async void InitAuth()
|
||||
{
|
||||
auth = Authenticator.Create(data.auth_type);
|
||||
await auth.Initialize();
|
||||
}
|
||||
|
||||
private void AfterConnected()
|
||||
{
|
||||
if (connected)
|
||||
return;
|
||||
|
||||
if (network.NetworkTickSystem != null)
|
||||
network.NetworkTickSystem.Tick += OnTick;
|
||||
connected = true;
|
||||
onConnect?.Invoke();
|
||||
}
|
||||
|
||||
private void AfterDisconnected()
|
||||
{
|
||||
if (!connected)
|
||||
return;
|
||||
|
||||
if (network.NetworkTickSystem != null)
|
||||
network.NetworkTickSystem.Tick -= OnTick;
|
||||
offline_mode = false;
|
||||
connected = false;
|
||||
onDisconnect?.Invoke();
|
||||
}
|
||||
|
||||
private void OnClientConnect(ulong client_id)
|
||||
{
|
||||
if (IsServer && client_id != ServerID)
|
||||
{
|
||||
Debug.Log("Client Connected: " + client_id);
|
||||
onClientJoin?.Invoke(client_id);
|
||||
}
|
||||
|
||||
if (!IsServer)
|
||||
AfterConnected(); //AfterConnected wasn't called yet for client
|
||||
}
|
||||
|
||||
private void OnClientDisconnect(ulong client_id)
|
||||
{
|
||||
if (IsServer && client_id != ServerID)
|
||||
{
|
||||
Debug.Log("Client Disconnected: " + client_id);
|
||||
onClientQuit?.Invoke(client_id);
|
||||
}
|
||||
|
||||
if (ClientID == client_id || client_id == ServerID)
|
||||
AfterDisconnected();
|
||||
}
|
||||
|
||||
private void OnTick()
|
||||
{
|
||||
onTick?.Invoke();
|
||||
}
|
||||
|
||||
private void ApprovalCheck(NetworkManager.ConnectionApprovalRequest req, NetworkManager.ConnectionApprovalResponse res)
|
||||
{
|
||||
ConnectionData connect = NetworkTool.NetDeserialize<ConnectionData>(req.Payload);
|
||||
bool approved = ApproveClient(req.ClientNetworkId, connect);
|
||||
res.Approved = approved;
|
||||
}
|
||||
|
||||
private bool ApproveClient(ulong client_id, ConnectionData connect)
|
||||
{
|
||||
if (client_id == ServerID)
|
||||
return true; //Server always approve itself
|
||||
|
||||
if (offline_mode)
|
||||
return false;
|
||||
|
||||
if (connect == null)
|
||||
return false; //Invalid data
|
||||
|
||||
if (string.IsNullOrEmpty(connect.username) || string.IsNullOrEmpty(connect.user_id))
|
||||
return false; //Invalid username
|
||||
|
||||
if (checkApproval != null && !checkApproval.Invoke(client_id, connect))
|
||||
return false; //Custom approval condition
|
||||
|
||||
return true; //New Client approved
|
||||
}
|
||||
|
||||
public IReadOnlyList<ulong> GetClientsIds()
|
||||
{
|
||||
return network.ConnectedClientsIds;
|
||||
}
|
||||
|
||||
public int CountClients()
|
||||
{
|
||||
if (offline_mode)
|
||||
return 1;
|
||||
if (IsServer && IsConnected())
|
||||
return network.ConnectedClientsIds.Count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public bool IsConnecting()
|
||||
{
|
||||
return IsActive() && !IsConnected(); //Trying to connect but not yet
|
||||
}
|
||||
|
||||
public bool IsConnected()
|
||||
{
|
||||
return offline_mode || network.IsServer || network.IsConnectedClient;
|
||||
}
|
||||
|
||||
public bool IsActive()
|
||||
{
|
||||
return offline_mode || network.IsServer || network.IsClient;
|
||||
}
|
||||
|
||||
public string Address
|
||||
{
|
||||
get { return transport.GetAddress(); }
|
||||
}
|
||||
|
||||
public ushort Port
|
||||
{
|
||||
get { return transport.GetPort(); }
|
||||
}
|
||||
|
||||
public ulong ClientID { get { return offline_mode ? ServerID : network.LocalClientId; } } //ID of this client (if host, will be same than ServerID), changes for every reconnection, assigned by Netcode
|
||||
public ulong ServerID { get { return NetworkManager.ServerClientId; } } //ID of the server
|
||||
|
||||
public bool IsServer { get { return offline_mode || network.IsServer; } }
|
||||
public bool IsClient { get { return offline_mode || network.IsClient; } }
|
||||
public bool IsHost { get { return IsClient && IsServer; } } //Host is both a client and server
|
||||
public bool IsOnline { get { return !offline_mode && IsActive(); } }
|
||||
|
||||
public NetworkTime LocalTime { get { return network.LocalTime; } }
|
||||
public NetworkTime ServerTime { get { return network.ServerTime; } }
|
||||
public float DeltaTick { get { return 1f / network.NetworkTickSystem.TickRate; } }
|
||||
|
||||
public NetworkManager NetworkManager { get { return network; } }
|
||||
public TcgTransport Transport { get { return transport; } }
|
||||
public NetworkMessaging Messaging { get { return messaging; } }
|
||||
public Authenticator Auth { get { return auth; } }
|
||||
|
||||
public static int MsgSizeMax { get { return msg_size; } }
|
||||
public static int MsgSize => MsgSizeMax; //Old name
|
||||
|
||||
public static TcgNetwork Get()
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
TcgNetwork net = FindObjectOfType<TcgNetwork>();
|
||||
net?.Init();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class ConnectionData : INetworkSerializable
|
||||
{
|
||||
public string user_id = "";
|
||||
public string username = "";
|
||||
|
||||
public byte[] extra = new byte[0];
|
||||
|
||||
//If you add extra data, make sure the total size of ConnectionData doesn't exceed Netcode max unfragmented msg (1400 bytes)
|
||||
//Fragmented msg are not possible for connection data, since connection is done in a single request
|
||||
|
||||
public string GetExtraString()
|
||||
{
|
||||
return NetworkTool.DeserializeString(extra);
|
||||
}
|
||||
|
||||
public T GetExtraData<T>() where T : INetworkSerializable, new()
|
||||
{
|
||||
return NetworkTool.NetDeserialize<T>(extra);
|
||||
}
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref user_id);
|
||||
serializer.SerializeValue(ref username);
|
||||
serializer.SerializeValue(ref extra);
|
||||
}
|
||||
}
|
||||
|
||||
public class SerializedData
|
||||
{
|
||||
private FastBufferReader reader;
|
||||
private INetworkSerializable data;
|
||||
private byte[] bytes;
|
||||
|
||||
public SerializedData(FastBufferReader r) { reader = r; data = null; }
|
||||
public SerializedData(INetworkSerializable d) { data = d; }
|
||||
|
||||
public string GetString()
|
||||
{
|
||||
reader.ReadValueSafe(out string msg);
|
||||
return msg;
|
||||
}
|
||||
|
||||
public T Get<T>() where T : INetworkSerializable, new()
|
||||
{
|
||||
if (data != null)
|
||||
{
|
||||
return (T)data;
|
||||
}
|
||||
else if (bytes != null)
|
||||
{
|
||||
data = NetworkTool.NetDeserialize<T>(bytes);
|
||||
return (T)data;
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.ReadNetworkSerializable(out T val);
|
||||
data = val;
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
//PreRead in advance without knowing the object type, since FastBufferReader will get disposed by netcode
|
||||
public void PreRead()
|
||||
{
|
||||
int size = reader.Length - reader.Position;
|
||||
bytes = new byte[size];
|
||||
reader.ReadBytesSafe(ref bytes, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/Network/TcgNetwork.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/Network/TcgNetwork.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bbe5bb65445eda14794157ae42758a1f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: -10
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
45
Assets/TcgEngine/Scripts/Network/TcgTransport.cs
Normal file
45
Assets/TcgEngine/Scripts/Network/TcgTransport.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Netcode.Transports.UTP;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TcgEngine
|
||||
{
|
||||
//Just a wrapper of UnityTransport to make it easier to replace with WebSocketTransport if planning to build for WebGL
|
||||
|
||||
public class TcgTransport : MonoBehaviour
|
||||
{
|
||||
//[Header("Client")]
|
||||
//[TextArea] public string chain;
|
||||
|
||||
//[Header("Server")]
|
||||
//[TextArea] public string cert;
|
||||
//[TextArea] public string key; //Set this on server only
|
||||
|
||||
private UnityTransport transport;
|
||||
|
||||
private const string listen_all = "0.0.0.0";
|
||||
|
||||
public virtual void Init()
|
||||
{
|
||||
transport = GetComponent<UnityTransport>();
|
||||
}
|
||||
|
||||
public virtual void SetServer(ushort port)
|
||||
{
|
||||
transport.ConnectionData.ServerListenAddress = listen_all;
|
||||
transport.SetConnectionData(listen_all, port);
|
||||
//transport.SetServerSecrets(cert, key);
|
||||
}
|
||||
|
||||
public virtual void SetClient(string address, ushort port)
|
||||
{
|
||||
string ip = NetworkTool.HostToIP(address);
|
||||
transport.SetConnectionData(ip, port);
|
||||
//transport.SetClientSecrets(address, chain);
|
||||
}
|
||||
|
||||
public virtual string GetAddress() { return transport.ConnectionData.Address; }
|
||||
public virtual ushort GetPort() { return transport.ConnectionData.Port; }
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/Network/TcgTransport.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/Network/TcgTransport.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d354098f233ef3c4e82b6136b46e83ef
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user