Merge pull request #19 from Tarnadas/master
[sm64o.git] / SM64O / WebSocketConnection.cs
blobc1ed34dad6f6c5080c47f5034a4cc781230a62d2
1 using System;
2 using System.Linq;
3 using System.Text;
4 using System.Collections.Generic;
5 using System.IO;
6 using System.IO.Compression;
7 using WebSocketSharp;
8 using WebSocketSharp.Server;
10 namespace SM64O {
11 public class WebSocketConnection : WebSocketBehavior
13 //private static List<WebSocketConnection> _ws = new List<WebSocketConnection>();
14 private static WebSocketConnection[] _connections = new WebSocketConnection[24];
15 private static int _index = 0;
17 private int _id;
18 private Client _client;
20 public WebSocketConnection()
22 if (_index > 24)
24 // Server is full
25 //Send("server is full");
26 this.Context.WebSocket.Close();
27 return;
29 //_id = _ws.Count;
30 _id = _index;
31 _index++;
32 _connections[_id] = this;
34 //try
35 //{
36 // TODO bans
37 /* if (_bands.Contains(e.Connection.EndPoint.ToString().Split(':')[0]))
39 sendChatTo("banned", e.Connection);
40 e.Connection.Close();
41 return;
42 } */
43 _client = new Client(this);
44 _client.Id = (byte)(_id + 1);
46 //}
47 //finally
48 //{
49 //Form1.Form.labelPlayersOnline.Text = "Players Online: " + (pos+1) + "/24";
50 //}
53 protected override void OnMessage(MessageEventArgs e)
55 byte[] data = e.RawData;
56 if (data.Length == 0) return;
58 PacketType type = (PacketType)data[0];
59 byte[] payload = data.Skip(1).ToArray();
61 switch (type)
63 case PacketType.Handshake:
64 onHandShake(payload);
65 break;
66 case PacketType.PlayerData:
67 onPlayerData(payload);
68 break;
69 case PacketType.ChatMessage:
70 onChatMessage(data);
71 break;
72 case PacketType.RoundtripPing:
73 _client.Connection.Context.WebSocket.Send(data);
74 break;
75 case PacketType.CharacterSwitch:
76 _client.SwitchCharacter((int)payload[0]);
77 break;
81 protected override void OnClose(CloseEventArgs e)
83 try {
84 Form1.Form.listBoxPlayers.Items.Remove(_client);
86 catch
88 // connection might not yet be open, ignore
91 _index--;
92 if (_id == _index)
94 // player with highest player ID left
95 _connections[_id] = null;
96 return;
98 // another player left
99 // move last player to his spot and resend player ID for moving player
100 _connections[_id] = _connections[_index];
101 byte id = (byte)(_id + 1);
102 _connections[_id]._client.Id = id;
103 _connections[_id]._id = _id;
106 _connections[_id]._client.SendPacket(PacketType.Handshake, new byte[]{ id });
108 catch
110 // connection might not yet be open, ignore
112 _connections[_index] = null;
114 string msg = string.Format("{0} left", _client.Username);
115 if (msg.Length > Form1.MAX_CHAT_LENGTH)
116 msg = msg.Substring(0, 24);
117 sendAllChat(msg);
120 private void onHandShake(byte[] payload)
122 _client.Major = payload[0];
123 _client.Minor = payload[1];
124 if ((int)_client.Major != Form1.COMPAT_MAJOR_VERSION || (int)_client.Minor != Form1.COMPAT_MINOR_VERSION) {
125 byte[] res = new byte[]{ _client.Major, _client.Minor };
126 _client.SendPacket(PacketType.WrongVersion, res);
127 return;
129 _client.CharacterId = (int)payload[2];
130 int usernameLength = (int)payload[3];
131 byte[] usernameBytes = new byte[usernameLength];
132 Array.Copy(payload, 4, usernameBytes, 0, usernameLength);
133 _client.Username = Encoding.ASCII.GetString(usernameBytes);
135 _client.SendPacket(PacketType.Handshake, new byte[]{ _client.Id });
136 _client.SendPacket(PacketType.GameMode, new byte[]{ 0 });
138 Form1.Form.listBoxPlayers.Items.Add(_client);
140 string msg = string.Format("{0} joined", _client.Username);
141 if (msg.Length > Form1.MAX_CHAT_LENGTH)
142 msg = msg.Substring(0, 24);
143 sendAllChat(msg);
146 private void onPlayerData(byte[] payload)
148 _client.SetPlayerData(payload);
151 private void onChatMessage(byte[] payload)
153 for (int i = 0; i < 24; i++)
157 _client.Connection.Context.WebSocket.Send(payload);
159 catch{}
163 private void sendAllChat(string message)
165 string name = "[SERVER]";
167 if (message.Length > Form1.MAX_CHAT_LENGTH)
168 message = message.Substring(0, Form1.MAX_CHAT_LENGTH);
170 if (name.Length > Form1.MAX_CHAT_LENGTH)
171 name = name.Substring(0, Form1.MAX_CHAT_LENGTH);
173 byte[] messageBytes = Encoding.ASCII.GetBytes(message);
174 byte[] usernameBytes = Encoding.ASCII.GetBytes(name);
175 byte[] payload = new byte[1 + messageBytes.Length + 1 + usernameBytes.Length];
176 payload[0] = (byte)messageBytes.Length;
177 Array.Copy(messageBytes, 0, payload, 1, messageBytes.Length);
178 payload[messageBytes.Length + 1] = (byte)usernameBytes.Length;
179 Array.Copy(usernameBytes, 0, payload, 1 + messageBytes.Length + 1, usernameBytes.Length);
181 for (int i = 0; i < 24; i++)
183 if (_connections[i] == null || _connections[i]._client == null) continue;
184 _connections[i]._client.SendPacket(PacketType.ChatMessage, payload);
188 public static void SendPlayerData()
190 byte[] payload = new byte[0];
191 for (int i = 0, j = 0; i < 24; i++)
193 if (_connections[i] == null) continue;
194 var client = _connections[i]._client;
195 if (client == null) continue;
196 if (client.PlayerData != null && client.PlayerData[3] != 0)
198 client.PlayerData[3] = client.Id;
199 Array.Resize<byte>(ref payload, j + 0x18);
200 Array.Copy(client.PlayerData, 0, payload, j, 0x18);
201 j += 0x18;
204 using (MemoryStream res = new MemoryStream())
206 using (GZipStream gs = new GZipStream(res, CompressionMode.Compress))
207 using (MemoryStream ms = new MemoryStream(payload))
209 ms.CopyTo(gs);
211 byte[] data = res.ToArray();
212 for (int i = 0; i < 24; i++)
214 if (_connections[i] == null || _connections[i]._client == null) continue;
215 _connections[i]._client.SendPacket(PacketType.PlayerData, data);
220 private static string PrintBytes(byte[] byteArray)
222 var sb = new StringBuilder("new byte[] { ");
223 for(var i = 0; i < byteArray.Length; i++)
225 var b = byteArray[i];
226 sb.Append(b);
227 if (i < byteArray.Length -1)
229 sb.Append(", ");
232 sb.Append(" }");
233 return sb.ToString();