init
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
#if UNITY_WEBGL
|
||||
using System.Runtime.InteropServices;
|
||||
#endif
|
||||
|
||||
namespace Mirror.SimpleWeb
|
||||
{
|
||||
internal static class SimpleWebJSLib
|
||||
{
|
||||
#if UNITY_WEBGL
|
||||
[DllImport("__Internal")]
|
||||
internal static extern bool IsConnected(int index);
|
||||
|
||||
#pragma warning disable CA2101 // Specify marshaling for P/Invoke string arguments
|
||||
[DllImport("__Internal")]
|
||||
#pragma warning restore CA2101 // Specify marshaling for P/Invoke string arguments
|
||||
internal static extern int Connect(string address, Action<int> openCallback, Action<int> closeCallBack, Action<int, IntPtr, int> messageCallback, Action<int> errorCallback);
|
||||
|
||||
[DllImport("__Internal")]
|
||||
internal static extern void Disconnect(int index);
|
||||
|
||||
[DllImport("__Internal")]
|
||||
internal static extern bool Send(int index, byte[] array, int offset, int length);
|
||||
#else
|
||||
internal static bool IsConnected(int index) => throw new NotSupportedException();
|
||||
|
||||
internal static int Connect(string address, Action<int> openCallback, Action<int> closeCallBack, Action<int, IntPtr, int> messageCallback, Action<int> errorCallback) => throw new NotSupportedException();
|
||||
|
||||
internal static void Disconnect(int index) => throw new NotSupportedException();
|
||||
|
||||
internal static bool Send(int index, byte[] array, int offset, int length) => throw new NotSupportedException();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 97b96a0b65c104443977473323c2ff35
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,141 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AOT;
|
||||
|
||||
namespace Mirror.SimpleWeb
|
||||
{
|
||||
#if !UNITY_2021_3_OR_NEWER
|
||||
// Unity 2019 doesn't have ArraySegment.ToArray() yet.
|
||||
public static class Extensions
|
||||
{
|
||||
public static byte[] ToArray(this ArraySegment<byte> segment)
|
||||
{
|
||||
byte[] array = new byte[segment.Count];
|
||||
Array.Copy(segment.Array, segment.Offset, array, 0, segment.Count);
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public class WebSocketClientWebGl : SimpleWebClient
|
||||
{
|
||||
static readonly Dictionary<int, WebSocketClientWebGl> instances = new Dictionary<int, WebSocketClientWebGl>();
|
||||
|
||||
/// <summary>
|
||||
/// key for instances sent between c# and js
|
||||
/// </summary>
|
||||
int index;
|
||||
|
||||
/// <summary>
|
||||
/// Queue for messages sent by high level while still connecting, they will be sent after onOpen is called.
|
||||
/// <para>
|
||||
/// This is a workaround for anything that calls Send immediately after Connect.
|
||||
/// Without this the JS websocket will give errors.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
Queue<byte[]> ConnectingSendQueue;
|
||||
|
||||
internal WebSocketClientWebGl(int maxMessageSize, int maxMessagesPerTick) : base(maxMessageSize, maxMessagesPerTick)
|
||||
{
|
||||
#if !UNITY_WEBGL || UNITY_EDITOR
|
||||
throw new NotSupportedException();
|
||||
#endif
|
||||
}
|
||||
|
||||
public bool CheckJsConnected() => SimpleWebJSLib.IsConnected(index);
|
||||
|
||||
public override void Connect(Uri serverAddress)
|
||||
{
|
||||
index = SimpleWebJSLib.Connect(serverAddress.ToString(), OpenCallback, CloseCallBack, MessageCallback, ErrorCallback);
|
||||
instances.Add(index, this);
|
||||
state = ClientState.Connecting;
|
||||
}
|
||||
|
||||
public override void Disconnect()
|
||||
{
|
||||
state = ClientState.Disconnecting;
|
||||
// disconnect should cause closeCallback and OnDisconnect to be called
|
||||
SimpleWebJSLib.Disconnect(index);
|
||||
}
|
||||
|
||||
public override void Send(ArraySegment<byte> segment)
|
||||
{
|
||||
if (segment.Count > maxMessageSize)
|
||||
{
|
||||
Log.Error($"Cant send message with length {segment.Count} because it is over the max size of {maxMessageSize}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == ClientState.Connected)
|
||||
{
|
||||
SimpleWebJSLib.Send(index, segment.Array, segment.Offset, segment.Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ConnectingSendQueue == null)
|
||||
ConnectingSendQueue = new Queue<byte[]>();
|
||||
ConnectingSendQueue.Enqueue(segment.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
void onOpen()
|
||||
{
|
||||
receiveQueue.Enqueue(new Message(EventType.Connected));
|
||||
state = ClientState.Connected;
|
||||
|
||||
if (ConnectingSendQueue != null)
|
||||
{
|
||||
while (ConnectingSendQueue.Count > 0)
|
||||
{
|
||||
byte[] next = ConnectingSendQueue.Dequeue();
|
||||
SimpleWebJSLib.Send(index, next, 0, next.Length);
|
||||
}
|
||||
ConnectingSendQueue = null;
|
||||
}
|
||||
}
|
||||
|
||||
void onClose()
|
||||
{
|
||||
// this code should be last in this class
|
||||
|
||||
receiveQueue.Enqueue(new Message(EventType.Disconnected));
|
||||
state = ClientState.NotConnected;
|
||||
instances.Remove(index);
|
||||
}
|
||||
|
||||
void onMessage(IntPtr bufferPtr, int count)
|
||||
{
|
||||
try
|
||||
{
|
||||
ArrayBuffer buffer = bufferPool.Take(count);
|
||||
buffer.CopyFrom(bufferPtr, count);
|
||||
|
||||
receiveQueue.Enqueue(new Message(buffer));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error($"onData {e.GetType()}: {e.Message}\n{e.StackTrace}");
|
||||
receiveQueue.Enqueue(new Message(e));
|
||||
}
|
||||
}
|
||||
|
||||
void onErr()
|
||||
{
|
||||
receiveQueue.Enqueue(new Message(new Exception("Javascript Websocket error")));
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
[MonoPInvokeCallback(typeof(Action<int>))]
|
||||
static void OpenCallback(int index) => instances[index].onOpen();
|
||||
|
||||
[MonoPInvokeCallback(typeof(Action<int>))]
|
||||
static void CloseCallBack(int index) => instances[index].onClose();
|
||||
|
||||
[MonoPInvokeCallback(typeof(Action<int, IntPtr, int>))]
|
||||
static void MessageCallback(int index, IntPtr bufferPtr, int count) => instances[index].onMessage(bufferPtr, count);
|
||||
|
||||
[MonoPInvokeCallback(typeof(Action<int>))]
|
||||
static void ErrorCallback(int index) => instances[index].onErr();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 015c5b1915fd1a64cbe36444d16b2f7d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1999985791b91b9458059e88404885a7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,114 @@
|
||||
// this will create a global object
|
||||
const SimpleWeb = {
|
||||
webSockets: [],
|
||||
next: 1,
|
||||
GetWebSocket: function (index) {
|
||||
return SimpleWeb.webSockets[index]
|
||||
},
|
||||
AddNextSocket: function (webSocket) {
|
||||
var index = SimpleWeb.next;
|
||||
SimpleWeb.next++;
|
||||
SimpleWeb.webSockets[index] = webSocket;
|
||||
return index;
|
||||
},
|
||||
RemoveSocket: function (index) {
|
||||
SimpleWeb.webSockets[index] = undefined;
|
||||
},
|
||||
};
|
||||
|
||||
function IsConnected(index) {
|
||||
var webSocket = SimpleWeb.GetWebSocket(index);
|
||||
if (webSocket) {
|
||||
return webSocket.readyState === webSocket.OPEN;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function Connect(addressPtr, openCallbackPtr, closeCallBackPtr, messageCallbackPtr, errorCallbackPtr) {
|
||||
// fix for unity 2021 because unity bug in .jslib
|
||||
if (typeof Runtime === "undefined") {
|
||||
// if unity doesn't create Runtime, then make it here
|
||||
// dont ask why this works, just be happy that it does
|
||||
Runtime = {
|
||||
dynCall: dynCall
|
||||
}
|
||||
}
|
||||
|
||||
const address = UTF8ToString(addressPtr);
|
||||
console.log("Connecting to " + address);
|
||||
// Create webSocket connection.
|
||||
webSocket = new WebSocket(address);
|
||||
webSocket.binaryType = 'arraybuffer';
|
||||
const index = SimpleWeb.AddNextSocket(webSocket);
|
||||
|
||||
// Connection opened
|
||||
webSocket.addEventListener('open', function (event) {
|
||||
console.log("Connected to " + address);
|
||||
Runtime.dynCall('vi', openCallbackPtr, [index]);
|
||||
});
|
||||
webSocket.addEventListener('close', function (event) {
|
||||
console.log("Disconnected from " + address);
|
||||
Runtime.dynCall('vi', closeCallBackPtr, [index]);
|
||||
});
|
||||
|
||||
// Listen for messages
|
||||
webSocket.addEventListener('message', function (event) {
|
||||
if (event.data instanceof ArrayBuffer) {
|
||||
// TODO dont alloc each time
|
||||
var array = new Uint8Array(event.data);
|
||||
var arrayLength = array.length;
|
||||
|
||||
var bufferPtr = _malloc(arrayLength);
|
||||
var dataBuffer = new Uint8Array(HEAPU8.buffer, bufferPtr, arrayLength);
|
||||
dataBuffer.set(array);
|
||||
|
||||
Runtime.dynCall('viii', messageCallbackPtr, [index, bufferPtr, arrayLength]);
|
||||
_free(bufferPtr);
|
||||
}
|
||||
else {
|
||||
console.error("message type not supported")
|
||||
}
|
||||
});
|
||||
|
||||
webSocket.addEventListener('error', function (event) {
|
||||
console.error('Socket Error', event);
|
||||
|
||||
Runtime.dynCall('vi', errorCallbackPtr, [index]);
|
||||
});
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
function Disconnect(index) {
|
||||
var webSocket = SimpleWeb.GetWebSocket(index);
|
||||
if (webSocket) {
|
||||
webSocket.close(1000, "Disconnect Called by Mirror");
|
||||
}
|
||||
|
||||
SimpleWeb.RemoveSocket(index);
|
||||
}
|
||||
|
||||
function Send(index, arrayPtr, offset, length) {
|
||||
var webSocket = SimpleWeb.GetWebSocket(index);
|
||||
if (webSocket) {
|
||||
const start = arrayPtr + offset;
|
||||
const end = start + length;
|
||||
const data = HEAPU8.buffer.slice(start, end);
|
||||
webSocket.send(data);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const SimpleWebLib = {
|
||||
$SimpleWeb: SimpleWeb,
|
||||
IsConnected,
|
||||
Connect,
|
||||
Disconnect,
|
||||
Send
|
||||
};
|
||||
autoAddDeps(SimpleWebLib, '$SimpleWeb');
|
||||
mergeInto(LibraryManager.library, SimpleWebLib);
|
||||
@@ -0,0 +1,37 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 54452a8c6d2ca9b49a8c79f81b50305c
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Facebook: WebGL
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
WebGL: WebGL
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user