Added multiplayer plugin

This commit is contained in:
Anthony Berg
2020-11-30 08:12:07 +00:00
parent 9cb342dd42
commit f64cf54803
450 changed files with 33131 additions and 10 deletions

View File

@@ -0,0 +1,25 @@
using System;
namespace Mirror.Cloud
{
public interface IBaseApi
{
/// <summary>
/// Cleans up any data created by the instance
/// <para>For Example: removing server from list</para>
/// </summary>
void Shutdown();
}
public abstract class BaseApi
{
protected readonly ICoroutineRunner runner;
protected readonly IRequestCreator requestCreator;
protected BaseApi(ICoroutineRunner runner, IRequestCreator requestCreator)
{
this.runner = runner ?? throw new ArgumentNullException(nameof(runner));
this.requestCreator = requestCreator ?? throw new ArgumentNullException(nameof(requestCreator));
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 70f563b7a7210ae43bbcde5cb7721a94
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
using System;
using Mirror.Cloud.ListServerService;
using UnityEngine.Events;
namespace Mirror.Cloud
{
[Serializable]
public class ServerListEvent : UnityEvent<ServerCollectionJson> { }
[Serializable]
public class MatchFoundEvent : UnityEvent<ServerJson> { }
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c7c472a3ea1bc4348bd5a0b05bf7cc3b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
using UnityEngine.Networking;
namespace Mirror.Cloud
{
public static class Extensions
{
public static bool IsOk(this UnityWebRequest webRequest)
{
return 200 <= webRequest.responseCode && webRequest.responseCode <= 299;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 97501e783fc67a4459b15d10e6c63563
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
using System.Collections;
using UnityEngine;
namespace Mirror.Cloud
{
public interface ICoroutineRunner : IUnityEqualCheck
{
Coroutine StartCoroutine(IEnumerator routine);
void StopCoroutine(IEnumerator routine);
void StopCoroutine(Coroutine routine);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 43472c60a7c72e54eafe559290dd0fc6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,42 @@
using System.Collections;
using UnityEngine.Networking;
namespace Mirror.Cloud
{
public delegate void RequestSuccess(string responseBody);
public delegate void RequestFail(string responseBody);
/// <summary>
/// Objects that can be sent to the Api must have this interface
/// </summary>
public interface ICanBeJson { }
/// <summary>
/// Methods to create and send UnityWebRequest
/// </summary>
public interface IRequestCreator
{
UnityWebRequest Delete(string page);
UnityWebRequest Get(string page);
UnityWebRequest Patch<T>(string page, T json) where T : struct, ICanBeJson;
UnityWebRequest Post<T>(string page, T json) where T : struct, ICanBeJson;
/// <summary>
/// Sends Request to api and invokes callback when finished
/// <para>Starts Coroutine of SendRequestEnumerator</para>
/// </summary>
/// <param name="request"></param>
/// <param name="onSuccess"></param>
/// <param name="onFail"></param>
void SendRequest(UnityWebRequest request, RequestSuccess onSuccess = null, RequestFail onFail = null);
/// <summary>
/// Sends Request to api and invokes callback when finished
/// </summary>
/// <param name="request"></param>
/// <param name="onSuccess"></param>
/// <param name="onFail"></param>
/// <returns></returns>
IEnumerator SendRequestEnumerator(UnityWebRequest request, RequestSuccess onSuccess = null, RequestFail onFail = null);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b80b95532a9d6e8418aa676a261e4f69
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,26 @@
using UnityEngine;
namespace Mirror.Cloud
{
/// <summary>
/// Adds Extension to check if unity object is null.
/// <para>Use these methods to stop MissingReferenceException</para>
/// </summary>
public interface IUnityEqualCheck
{
}
public static class UnityEqualCheckExtension
{
public static bool IsNull(this IUnityEqualCheck obj)
{
return (obj as Object) == null;
}
public static bool IsNotNull(this IUnityEqualCheck obj)
{
return (obj as Object) != null;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 05185b973ba389a4588fc8a99c75a4f6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,24 @@
using System;
namespace Mirror.Cloud
{
[Serializable]
public struct CreatedIdJson : ICanBeJson
{
public string id;
}
[Serializable]
public struct ErrorJson : ICanBeJson
{
public string code;
public string message;
public int HtmlCode => int.Parse(code);
}
[Serializable]
public struct EmptyJson : ICanBeJson
{
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0688c0fdae5376e4ea74d5c3904eed17
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,72 @@
using System;
using UnityEngine;
using UnityEngine.Networking;
namespace Mirror.Cloud
{
public static class Logger
{
public static bool VerboseLogging = false;
static readonly ILogger logger = LogFactory.GetLogger("MirrorCloudServices");
public static void LogRequest(string page, string method, bool hasJson, string json)
{
if (hasJson)
{
logger.LogFormat(LogType.Log, "Request: {0} {1} {2}", method, page, json);
}
else
{
logger.LogFormat(LogType.Log, "Request: {0} {1}", method, page);
}
}
public static void LogResponse(UnityWebRequest statusRequest)
{
long code = statusRequest.responseCode;
LogType logType = statusRequest.IsOk()
? LogType.Log
: LogType.Error;
string format = "Response: {0} {1} {2} {3}";
if (logger.IsLogTypeAllowed(logType))
{
// we split path like this to make sure api key doesn't leak
Uri uri = new Uri(statusRequest.url);
string path = string.Join("", uri.Segments);
string msg = string.Format(format, statusRequest.method, code, path, statusRequest.downloadHandler.text);
logger.Log(logType, msg);
}
if (!string.IsNullOrEmpty(statusRequest.error))
{
string msg = string.Format("WEB REQUEST ERROR: {0}", statusRequest.error);
logger.Log(LogType.Error, msg);
}
}
internal static void Log(string msg)
{
if (logger.LogEnabled())
logger.Log(msg);
}
internal static void LogWarning(string msg)
{
if (logger.WarnEnabled())
logger.LogWarning(msg);
}
internal static void LogError(string msg)
{
if (logger.ErrorEnabled())
logger.LogError(msg);
}
internal static void Verbose(string msg)
{
if (VerboseLogging && logger.LogEnabled())
logger.Log(msg);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 457ba2df6cb6e1542996c17c715ee81b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,144 @@
using System;
using System.Collections;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;
namespace Mirror.Cloud
{
/// <summary>
/// Methods to create and send UnityWebRequest
/// </summary>
public class RequestCreator : IRequestCreator
{
const string GET = "GET";
const string POST = "POST";
const string PATCH = "PATCH";
const string DELETE = "DELETE";
public readonly string baseAddress;
public readonly string apiKey;
readonly ICoroutineRunner runner;
public RequestCreator(string baseAddress, string apiKey, ICoroutineRunner coroutineRunner)
{
if (string.IsNullOrEmpty(baseAddress))
{
throw new ArgumentNullException(nameof(baseAddress));
}
if (string.IsNullOrEmpty(apiKey))
{
throw new ArgumentNullException(nameof(apiKey));
}
this.baseAddress = baseAddress;
this.apiKey = apiKey;
runner = coroutineRunner ?? throw new ArgumentNullException(nameof(coroutineRunner));
}
Uri CreateUri(string page)
{
return new Uri(string.Format("{0}/{1}?key={2}", baseAddress, page, apiKey));
}
UnityWebRequest CreateWebRequest(string page, string method, string json = null)
{
bool hasJson = !string.IsNullOrEmpty(json);
Logger.LogRequest(page, method, hasJson, json);
UnityWebRequest request = new UnityWebRequest(CreateUri(page));
request.method = method;
if (hasJson)
{
request.SetRequestHeader("Content-Type", "application/json");
}
request.downloadHandler = new DownloadHandlerBuffer();
byte[] bodyRaw = hasJson
? Encoding.UTF8.GetBytes(json)
: null;
request.uploadHandler = new UploadHandlerRaw(bodyRaw);
return request;
}
/// <summary>
/// Create Get Request to page
/// </summary>
/// <param name="page"></param>
/// <returns></returns>
public UnityWebRequest Get(string page)
{
return CreateWebRequest(page, GET);
}
/// <summary>
/// Creates Post Request to page with Json body
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="page"></param>
/// <param name="json"></param>
/// <returns></returns>
public UnityWebRequest Post<T>(string page, T json) where T : struct, ICanBeJson
{
string jsonString = JsonUtility.ToJson(json);
return CreateWebRequest(page, POST, jsonString);
}
/// <summary>
/// Creates Patch Request to page with Json body
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="page"></param>
/// <param name="json"></param>
/// <returns></returns>
public UnityWebRequest Patch<T>(string page, T json) where T : struct, ICanBeJson
{
string jsonString = JsonUtility.ToJson(json);
return CreateWebRequest(page, PATCH, jsonString);
}
/// <summary>
/// Create Delete Request to page
/// </summary>
/// <param name="page"></param>
/// <returns></returns>
public UnityWebRequest Delete(string page)
{
return CreateWebRequest(page, DELETE);
}
public void SendRequest(UnityWebRequest request, RequestSuccess onSuccess = null, RequestFail onFail = null)
{
runner.StartCoroutine(SendRequestEnumerator(request, onSuccess, onFail));
}
public IEnumerator SendRequestEnumerator(UnityWebRequest request, RequestSuccess onSuccess = null, RequestFail onFail = null)
{
using (UnityWebRequest webRequest = request)
{
yield return webRequest.SendWebRequest();
Logger.LogResponse(webRequest);
string text = webRequest.downloadHandler.text;
Logger.Verbose(text);
if (webRequest.IsOk())
{
onSuccess?.Invoke(text);
}
else
{
onFail?.Invoke(text);
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cfaa626443cc7c94eae138a2e3a04d7c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: