Skip to content

Commit 4c90826

Browse files
author
David Douglas
committed
UnityWebSocket using websocket-sharp
0 parents  commit 4c90826

16 files changed

+439
-0
lines changed

.editorconfig

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# EditorConfig is awesome: http://EditorConfig.org
2+
3+
root = true
4+
5+
[*]
6+
indent_style = space
7+
indent_size = 2
8+
insert_final_newline = true
9+
trim_trailing_whitespace = true
10+
end_of_line = lf
11+
charset = utf-8
12+
13+
[*.json]
14+
insert_final_newline = ignore
15+

.gitignore

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/[Ll]ibrary/
2+
/[Tt]emp/
3+
/[Oo]bj/
4+
/[Bb]uild/
5+
/[Bb]uilds/
6+
/Assets/AssetStoreTools*
7+
8+
# Visual Studio 2015 cache directory
9+
/.vs/
10+
11+
# Autogenerated VS/MD/Consulo solution and project files
12+
ExportedObj/
13+
.consulo/
14+
*.csproj
15+
*.unityproj
16+
*.sln
17+
*.suo
18+
*.tmp
19+
*.user
20+
*.userprefs
21+
*.pidb
22+
*.booproj
23+
*.svd
24+
*.pdb
25+
26+
# Unity3D generated meta files
27+
*.pidb.meta
28+
*.meta
29+
30+
# Unity3D Generated File On Crash Reports
31+
sysinfo.txt
32+
33+
# Builds
34+
*.apk
35+
*.unitypackage
36+
37+
# IDEs
38+
#/.vscode
39+
#omnisharp.json
40+
#.editorconfig

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "Dependencies/websocket-sharp"]
2+
path = Dependencies/websocket-sharp
3+
url = https://github.com/sta/websocket-sharp

Dependencies/websocket-sharp

Submodule websocket-sharp added at d532640

Events/DataEventArgs.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System;
2+
3+
namespace UnityWebSocket {
4+
public class DataEventArgs : EventArgs {
5+
public byte[] Data { get; private set; }
6+
7+
public DataEventArgs(byte[] data) {
8+
this.Data = data;
9+
}
10+
}
11+
}

Events/TextEventArgs.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System;
2+
3+
namespace UnityWebSocket {
4+
public class TextEventArgs : EventArgs {
5+
public string Text { get; private set; }
6+
7+
public TextEventArgs(string text) {
8+
this.Text = text;
9+
}
10+
}
11+
}

Handlers/DataHandler.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using UnityEngine;
5+
using UnityEngine.Events;
6+
using System;
7+
8+
// This handler takes the web socket data bytes and raises a received data event.
9+
// This allows us to parse the bytes data in one place and then raise an event to feed game object recievers or a controller to target multiple game objects.
10+
namespace UnityWebSocket {
11+
public abstract class DataHandler : MonoBehaviour, IDataHandler {
12+
// A game object can implement this received data event to get updates.
13+
public delegate void ReceivedData(object sender, EventArgs e);
14+
public static event ReceivedData OnReceivedData;
15+
16+
// Override this method in your own subclass to pass any custom event args
17+
public virtual void OnData(byte[] data) {
18+
Debug.LogFormat("Received data:\n{0}", data.Length);
19+
RaiseOnReceivedData(this, new DataEventArgs(data));
20+
}
21+
22+
protected void RaiseOnReceivedData(object sender, EventArgs e) {
23+
// Raise the event
24+
OnReceivedData(this, e);
25+
}
26+
27+
#region Unity lifecycle
28+
29+
// Web Socket data handler
30+
void OnEnable() {
31+
UnityWebSocket.OnData += OnData;
32+
}
33+
34+
void OnDisable() {
35+
UnityWebSocket.OnData -= OnData;
36+
}
37+
38+
#endregion
39+
}
40+
}

Handlers/IDataHandler.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
using UnityEngine;
4+
5+
namespace UnityWebSocket {
6+
public interface IDataHandler {
7+
void OnData(byte[] data);
8+
}
9+
}

Handlers/TextHandler.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using UnityEngine;
5+
using System.Text;
6+
using System;
7+
8+
namespace UnityWebSocket {
9+
public class TextHandler : DataHandler {
10+
// Web Socket handler passes text event args
11+
public override void OnData(byte[] data) {
12+
RaiseOnReceivedData(this, new TextEventArgs(Encoding.UTF8.GetString(data)));
13+
}
14+
}
15+
}

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2018 David Douglas
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Web Sockets for Unity
2+
3+
For Unity developers looking to use Web Sockets in their Unity game / app.
4+
5+
## External dependencies
6+
**First download the required dependencies and extract the contents into your Unity project "Assets" folder.**
7+
- [WebSocket-Sharp](https://github.com/sta/websocket-sharp)
8+
9+
## :octocat: Download instructions
10+
This project contains git submodule dependencies so use:
11+
12+
`git clone --recursive https://github.com/Unity3dAzure/UnityWebSocket.git`
13+
14+
Or if you've already done a git clone then use:
15+
16+
`git submodule update --init --recursive`
17+
18+
## Developer notes
19+
20+
When using Unity 2017.2.1p2 and the .NET 4.6 API (Experimental) player settings I tried the system [ClientWebSocket](https://msdn.microsoft.com/en-us/library/system.net.websockets.clientwebsocket%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396). While this initially had some success the problem was that after 3 mins or so the following error would occur on the async/await connect function:
21+
22+
```
23+
ObjectDisposedException: Cannot access a disposed object.
24+
Object name: 'System.Net.Sockets.NetworkStream'
25+
```
26+
27+
Therefore I opted for [WebSocket-Sharp](https://github.com/sta/websocket-sharp) which targets .NET Framework 3.5 and works in the Unity 2017 editor and doesn't seem to have the same issue.
28+
29+
Questions or tweet [@deadlyfingers](https://twitter.com/deadlyfingers)

Receivers/DataReceiver.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using UnityEngine;
5+
6+
namespace UnityWebSocket {
7+
public abstract class DataReceiver : MonoBehaviour, IDataReceiver {
8+
9+
// Override this method in your own subclass to process the received event data
10+
virtual public void OnReceivedData(object sender, EventArgs args) {
11+
Debug.Log("Hey we got some bytes to do something with!");
12+
}
13+
14+
#region Unity lifecycle
15+
16+
virtual public void OnEnable() {
17+
DataHandler.OnReceivedData += OnReceivedData;
18+
}
19+
20+
virtual public void OnDisable() {
21+
DataHandler.OnReceivedData -= OnReceivedData;
22+
}
23+
24+
#endregion
25+
}
26+
}

Receivers/IDataReceiver.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
using System;
2+
3+
namespace UnityWebSocket {
4+
public interface IDataReceiver {
5+
void OnReceivedData(object sender, EventArgs args);
6+
}
7+
}

Receivers/TextMeshReceiver.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using UnityEngine;
5+
using UnityEngine.UI;
6+
7+
namespace UnityWebSocket {
8+
// Drop this script onto a TextMesh gameobject to make it update
9+
public class TextMeshReceiver : DataReceiver {
10+
11+
private string text;
12+
private TextMesh textMesh;
13+
private bool needsUpdated = false;
14+
15+
void Awake() {
16+
textMesh = gameObject.GetComponent<TextMesh>();
17+
}
18+
19+
void Update() {
20+
// update any text components on this gameobject
21+
if (textMesh != null) {
22+
textMesh.text = text;
23+
needsUpdated = false;
24+
}
25+
}
26+
27+
// Override this method in your own subclass to process the received event data
28+
override public void OnReceivedData(object sender, EventArgs args) {
29+
if (args == null) {
30+
return;
31+
}
32+
33+
// return early if wrong type of EventArgs
34+
var myArgs = args as TextEventArgs;
35+
if (myArgs == null) {
36+
return;
37+
}
38+
39+
text = myArgs.Text;
40+
needsUpdated = true;
41+
}
42+
}
43+
44+
}

UnityWebSocket.cs

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using UnityEngine;
5+
using WebSocketSharp;
6+
using System.Text;
7+
using UnityEngine.UI;
8+
9+
namespace UnityWebSocket {
10+
public class UnityWebSocket : MonoBehaviour {
11+
// Web Socket data delegate
12+
public delegate void Data(byte[] data);
13+
public static Data OnData;
14+
15+
// Unity Inspector fields
16+
[SerializeField]
17+
private string webSocketUri = "ws://127.0.0.1:8080";
18+
[SerializeField]
19+
private bool AutoConnect = false;
20+
21+
private WebSocket _ws;
22+
private bool isReady = false;
23+
24+
void OnEnable() {
25+
if (AutoConnect) {
26+
ConnectWebSocket();
27+
}
28+
}
29+
30+
void OnDisable() {
31+
DisconnectWebSocket();
32+
}
33+
34+
public void Connect() {
35+
ConnectWebSocket();
36+
}
37+
38+
public void Close() {
39+
DisconnectWebSocket();
40+
}
41+
42+
public void SendText(string text) {
43+
byte[] data = Encoding.UTF8.GetBytes(text);
44+
SendBytes(data, null);
45+
}
46+
47+
public void SendInputText(InputField inputField) {
48+
SendText(inputField.text);
49+
}
50+
51+
public void SendBytes(byte[] data, Action<bool> callback = null) {
52+
if (_ws == null || _ws.ReadyState != WebSocketSharp.WebSocketState.Open) {
53+
Debug.LogWarning("Web socket is not available to send message. Try connecting?");
54+
return;
55+
}
56+
_ws.SendAsync(data, callback);
57+
}
58+
59+
private void ConnectWebSocket() {
60+
if (_ws == null) {
61+
Debug.Log("Create web socket uri: " + webSocketUri);
62+
_ws = new WebSocket(webSocketUri);
63+
}
64+
65+
if (!isReady) {
66+
Debug.Log("Connect web socket");
67+
isReady = true;
68+
_ws.OnError += OnWebSocketError;
69+
_ws.OnOpen += OnWebSocketOpen;
70+
_ws.OnMessage += OnWebSocketMessage;
71+
_ws.OnClose += OnWebSocketClose;
72+
_ws.ConnectAsync();
73+
}
74+
}
75+
76+
private void DisconnectWebSocket() {
77+
if (_ws != null && isReady) {
78+
Debug.Log("Disconnect web socket");
79+
_ws.CloseAsync();
80+
_ws.OnError -= OnWebSocketError;
81+
_ws.OnOpen -= OnWebSocketOpen;
82+
_ws.OnMessage -= OnWebSocketMessage;
83+
_ws.OnClose -= OnWebSocketClose;
84+
isReady = false;
85+
}
86+
}
87+
88+
private void OnWebSocketOpen(object sender, EventArgs e) {
89+
Debug.Log("Web socket is open");
90+
}
91+
92+
private void OnWebSocketClose(object sender, CloseEventArgs e) {
93+
Debug.Log("Web socket closed with reason: " + e.Reason);
94+
if (!e.WasClean) {
95+
DisconnectWebSocket();
96+
}
97+
}
98+
99+
private void OnWebSocketMessage(object sender, MessageEventArgs e) {
100+
Debug.Log("Web socket message:\n" + e.Data);
101+
// Raise web socket data handler event
102+
OnData(e.RawData);
103+
}
104+
105+
private void OnWebSocketError(object sender, ErrorEventArgs e) {
106+
Debug.LogError("Web socket error: " + e.Message);
107+
DisconnectWebSocket();
108+
}
109+
110+
}
111+
112+
}
113+

0 commit comments

Comments
 (0)