public static void AcceptCallback(IAsyncResult ar) { m_AcceptEvent.Set (); Socket webSocket = m_ListeningSocket.EndAccept (ar); WebSocketClient client = new WebSocketClient (webSocket); UOJS.Log ("Client [{0}]: Connection Detected", client.WebSocket.RemoteEndPoint); webSocket.BeginReceive (client.WriteBuffer, 0, client.WriteBuffer.Length, SocketFlags.None, new AsyncCallback (ReadCallback), client); }
public static void Send(WebSocketClient client, byte[] data, RequestType type, bool mask) { // masking isn't needed? int headerLength = 2; byte payload = 0; byte[] maskKeys = null; byte[] tmp = new byte[data.Length + 1]; tmp [0] = (byte)type; Array.Copy (data, 0, tmp, 1, data.Length); data = tmp; //data = Encoding.UTF8.GetBytes(((char)type) + Convert.ToBase64String(data)); //data = Encoding.UTF8.GetBytes(Encoding.ASCII.GetString(data)); //Console.WriteLine("Raw length={0}", data.Length); if (data.Length > short.MaxValue) UOJS.Log ("Client [{0}]: Sending Really Large Packet (not implemented)", client.WebSocket.RemoteEndPoint); if (data.Length >= 126) { headerLength += 2; payload = 126; } else payload = (byte)data.Length; if (mask) { headerLength += 4; Random r = new Random (); maskKeys = new byte[] { 1, 2, 3, 4 }; r.NextBytes (maskKeys); } byte[] allData = new byte[headerLength + data.Length]; allData [0] = 0x80 | 0x02; allData [1] = (byte)((mask ? 0x80 : 0) | payload & 0x40 | payload & 0x20 | payload & 0x10 | payload & 0x8 | payload & 0x4 | payload & 0x2 | payload & 0x1); if (payload == 126) { byte[] lengthBytes = BitConverter.GetBytes ((ushort)data.Length); allData [2] = lengthBytes [1]; // (byte)((data.Length >> 8) & 0xFF); allData [3] = lengthBytes [0]; // (byte)(data.Length & 0xFF); } Array.Copy (data, 0, allData, headerLength, data.Length); if (mask) { Array.Copy (maskKeys, 0, allData, 2, 4); for (int i = 0; i < data.Length; i++) allData [i + headerLength] ^= maskKeys [i % 4]; } if (client.WebSocket != null && client.WebSocket.Connected) { client.WebSocket.BeginSend (allData, 0, allData.Length, SocketFlags.None, new AsyncCallback (SendCallback), client); } }
public static void Send(WebSocketClient client, string format, params object[] o) { GameProxy.Send (client, m_Encoding.GetBytes (string.Format (format, o)), RequestType.WebRequest, false); }
public static byte[] ParseWebRequest(WebSocketClient client, string shortUri, string fullUri) { try { switch (shortUri) { case "/td": { Dictionary<string, string> query = ParseVars (fullUri); int id = int.Parse (query ["id"]); Dictionary<string, string> dict = new Dictionary<string, string> (); PropertyInfo info = m_Ultima.GetType ("Ultima.TileData").GetProperty ("ItemTable", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); Type itemData = m_Ultima.GetType ("Ultima.ItemData"); object o = ((Array)info.GetValue (null, null)).GetValue (id); PropertyInfo[] pubInfo = itemData.GetProperties (); foreach (PropertyInfo p in pubInfo) dict.Add (p.Name, p.GetValue (o, null).ToString ()); return m_Encoding.GetBytes (LitJson.JsonMapper.ToJson (dict)); } case "/getmapinfo": { Dictionary<string, string> query = ParseVars (fullUri); int x = int.Parse (query ["x"]), y = int.Parse (query ["y"]), range = int.Parse (query ["r"]); char facet = query ["m"] [0]; string map; switch (facet) { default: case 'f': map = "Felucca"; break; case 't': map = "Trammel"; break; case 'i': map = "Ilshenar"; break; case 'm': map = "Malas"; break; case 'o': map = "Tokuno"; break; // whoops } Type Map = m_Ultima.GetType ("Ultima.Map"); Type Tile = m_Ultima.GetType ("Ultima.Tile"); Type HuedTile = m_Ultima.GetType ("Ultima.HuedTile"); Type TileMatrix = m_Ultima.GetType ("Ultima.TileMatrix"); Dictionary<string, Dictionary<string, Dictionary<string, object>>> data = new Dictionary<string, Dictionary<string, Dictionary<string, object>>> (); object currentMap = ((FieldInfo)Map.GetMember (map) [0]).GetValue (null); object tiles = Map.GetProperty ("Tiles").GetValue (currentMap, null); for (int i = 0; i < range; i++) { Dictionary<string, Dictionary<string, object>> row; data.Add ((i + x).ToString (), row = new Dictionary<string, Dictionary<string, object>> ()); for (int j = 0; j < range; j++) { Dictionary<string, object> cell = new Dictionary<string, object> (); object landTile = TileMatrix.GetMethod ("GetLandTile").Invoke (tiles, new object[]{x + i, y + j}); Array staticTiles = (Array)TileMatrix.GetMethod ("GetStaticTiles").Invoke (tiles, new object[]{x + i, y + j}); int id = (int)Tile.GetProperty ("ID").GetValue (landTile, null); int z = (int)Tile.GetProperty ("Z").GetValue (landTile, null); cell.Add ("id", id); cell.Add ("z", z); cell.Add ("length", staticTiles.Length); TileInfo[] stiles = new TileInfo[staticTiles.Length]; for (int k = 0; k < stiles.Length; k++) { stiles [k].ID = (int)(HuedTile.GetProperty ("ID").GetValue (staticTiles.GetValue (k), null)) % 0x4000; stiles [k].Hue = (int)HuedTile.GetProperty ("Hue").GetValue (staticTiles.GetValue (k), null); stiles [k].Z = (int)HuedTile.GetProperty ("Z").GetValue (staticTiles.GetValue (k), null); } cell.Add ("o", stiles); row.Add ((j + y).ToString (), cell); } } return m_Encoding.GetBytes (LitJson.JsonMapper.ToJson (data)); } case "/getgump": { Dictionary<string, string> query = ParseVars (fullUri); foreach (KeyValuePair<string, string> kvp in query) Console.WriteLine (kvp); int id = int.Parse (query ["id"]); Type Gumps = m_Ultima.GetType ("Ultima.Gumps"); //int hueIdx = int.Parse (query ["h"]); //Hue hue = hueIdx == 0 ? null : Hues.List [(hueIdx & 0x3FFF) - 1]; //Bitmap b = (Bitmap)(Gumps.GetGump (id).Clone ()); Bitmap b = (Bitmap)Gumps.GetMethod ("GetGump", new Type[]{typeof(Int32)}).Invoke (null, new object[]{id}); //if (hue != null) // hue.ApplyTo (b, true); MemoryStream ms = new MemoryStream (); b.Save (ms, System.Drawing.Imaging.ImageFormat.Png); return ms.GetBuffer (); } case "/getobj": { Dictionary<string, string> query = ParseVars (fullUri); char type = query ["t"] [0]; int id = int.Parse (query ["i"]); int hueIdx = int.Parse (query ["h"]); string crop = query.ContainsKey ("c") ? query ["c"] : ""; Type Art = m_Ultima.GetType ("Ultima.Art"); Bitmap b = (Bitmap)(Art.GetMethod (type == 'l' ? "GetLand" : "GetStatic", new Type[]{typeof(Int32)}).Invoke (null, new object[]{id})); //Bitmap b = (Bitmap)(type == 'l' ? Art.GetLand (id) : Art.GetStatic (id)); //don't hue the cached, clone it //if (b == null) // b = Art.GetLand (0); b = (Bitmap)b.Clone (); //TODO: clone before hue (prevent modifying cache object) //Hue hue = hueIdx == 0 ? null : Hues.List [(hueIdx & 0x3FFF) - 1]; //if (hue != null) // hue.ApplyTo (b, type == 'l'); switch (crop) { // why can't this be done on the client side by only drawing half after // the transformation? set the sX to the half or set the sW to the half // depending on the side?? case "right": { for (int x = 0; x < b.Width/2; x++) { for (int y = 0; y < b.Height; y++) { b.SetPixel (x, y, Color.Transparent); } } break; } case "left": { for (int x = b.Width/2; x < b.Width; x++) { for (int y = 0; y < b.Height; y++) { b.SetPixel (x, y, Color.Transparent); } } break; } } MemoryStream ms = new MemoryStream (); b.Save (ms, System.Drawing.Imaging.ImageFormat.Png); return ms.GetBuffer (); } case "/getcliloc": { Dictionary<string, string> query = ParseVars (fullUri); int message = int.Parse (query ["i"]), i = 0; Type StringList = m_Ultima.GetType ("Ultima.StringList"); System.Collections.Hashtable table = (System.Collections.Hashtable)StringList.GetProperty ("Table").GetValue (StringList.GetProperty ("EnglishStringList", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy).GetValue (null, null), null); if (!table.ContainsKey (message)) return m_Encoding.GetBytes ("{\"text\": null}"); string entry = (string)table [message]; return UTF8Encoding.UTF8.GetBytes (entry); //string replace = Regex.Replace (entry, @"~[A-Za-z0-9_]+~", match => (query.ContainsKey ("" + (++i)) ? query ["" + (i)] : "")); //return UTF8Encoding.UTF8.GetBytes ("{\"text\":\"" + replace.Replace ("\"", "\\\"") + "\"}"); } case "/getaniminfo": { Dictionary<string, string> query = ParseVars (fullUri); int bodyId = int.Parse (query ["i"]); int action = int.Parse (query ["a"]); int dir = int.Parse (query ["d"]); int hash = (bodyId << 16) | (action << 8) | (dir); byte[] widths = null; if (m_Widths.ContainsKey (hash)) widths = m_Widths [hash]; else { Type Animations = m_Ultima.GetType ("Ultima.Animations"); Type Frame = m_Ultima.GetType ("Ultima.Frame"); Array frames = (Array)Animations.GetMethod ("GetAnimation").Invoke (null, new object[] { bodyId, action, dir, 0, true }); //Frame[] frames = Animations.GetAnimation (bodyId, action, dir, 0, true); if (frames == null) widths = new byte[0]; else { widths = new byte[frames.Length]; for (int i = 0; i < frames.Length; i++) { System.Drawing.Bitmap b = (System.Drawing.Bitmap)Frame.GetProperty ("Bitmap").GetValue (frames.GetValue (i), null); widths [i] = (byte)b.Width; } } } List<string> tmp = new List<string> (); foreach (byte b in widths) tmp.Add (b.ToString ()); return ASCIIEncoding.ASCII.GetBytes ("{\"widths\": [" + string.Join (",", tmp.ToArray ()) + "]}"); } case "/getanim": { //todo: check if wearable and adjust bitmap accordingly if human Dictionary<string, string> query = ParseVars (fullUri); int bodyId = int.Parse (query ["i"]); int action = int.Parse (query ["a"]); int dir = int.Parse (query ["d"]); int hueIdx = int.Parse (query ["h"]); Type Animations = m_Ultima.GetType ("Ultima.Animations"); Type Frame = m_Ultima.GetType ("Ultima.Frame"); Array frames = (Array)Animations.GetMethod ("GetAnimation").Invoke (null, new object[] { bodyId, action, dir, 0, true }); //Frame[] frames = Animations.GetAnimation (bodyId, action, dir, 0, true); //Hue hue = hueIdx == 0 ? null : Hues.List [(hueIdx & 0x3FFF) - 1]; int hash = (bodyId << 16) | (action << 8) | (dir); if (frames == null) return new byte[] { }; int maxWidth = 0, maxHeight = 0; for (int i = 0; i < frames.Length; i++) { System.Drawing.Bitmap b = (System.Drawing.Bitmap)Frame.GetProperty ("Bitmap").GetValue (frames.GetValue (i), null); if (b.Width > maxWidth) maxWidth = b.Width; // +Math.Abs(frame.Center.X); if (b.Height > maxHeight) maxHeight = b.Height; // +Math.Abs(frame.Center.Y); } // should we cache full animation bitmaps? Bitmap bitmap = new Bitmap (maxWidth * frames.Length, maxHeight); Graphics g = Graphics.FromImage (bitmap); byte[] widths = new byte[frames.Length]; for (int i = 0; i < frames.Length; i++) { object frame = frames.GetValue (i); System.Drawing.Bitmap single = (System.Drawing.Bitmap)Frame.GetProperty ("Bitmap").GetValue (frames.GetValue (i), null); widths [i] = (byte)single.Width; g.DrawImageUnscaled (single, i * maxWidth, 0); } if (!m_Widths.ContainsKey (hash)) m_Widths.Add (hash, widths); //if (hueIdx != 0) // hue.ApplyTo (bitmap, TileData.AnimationData.ContainsKey (bodyId) && (TileData.AnimationData [bodyId].Flags & TileFlag.PartialHue) != 0); bitmap.SetPixel (0, 0, Color.FromArgb (0, 0, 0, frames.Length)); MemoryStream ms = new MemoryStream (); bitmap.Save (ms, System.Drawing.Imaging.ImageFormat.Png); return ms.GetBuffer (); } } } catch (Exception e) { UOJS.Log ("Error {0}\r\n{1}", e.Message, e.StackTrace); return ASCIIEncoding.ASCII.GetBytes (string.Format ("An error has occurred: {0}\r\n{1}", e.Message, e.StackTrace)); } return new byte[] { }; }
public static void OnReceiveFromWebSocket(WebSocketClient client, byte[] data, int length) { try { switch ((char)data [0]) { // Reconnect case 'R': { if (client.UOSocket != null && client.UOSocket.Connected) client.UOSocket.Close (); goto case 'C'; } // Connect case 'C': { string[] strData = Encoding.ASCII.GetString (data, 0, data.Length).Split (' '); for (int i = 0; i < strData.Length; i++) Console.Write (strData [i] + ","); client.UOSocket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); Console.WriteLine (string.Join (",", strData)); client.UOSocket.BeginConnect (strData [1], int.Parse (strData [2]), new AsyncCallback (UOConnectCallback), client); break; } // Version case 'V': { GameProxy.Send (client, "Version {0}", UOJS.Version); break; } default: { client.UOSocket.BeginSend (data, 0, data.Length, SocketFlags.None, new AsyncCallback (UOSendCallback), client); break; } } } catch (Exception e) { UOJS.Log ("Client [d/c]: Threw {0}... closing!", e.GetType ()); UOJS.Log (e.StackTrace); client.Close (); } }