diff --git a/OpenRA.Server/Connection.cs b/OpenRA.Server/Connection.cs index fd547df34d..bb7246386e 100644 --- a/OpenRA.Server/Connection.cs +++ b/OpenRA.Server/Connection.cs @@ -15,6 +15,9 @@ namespace OpenRA.Server public int ExpectLength = 8; public int Frame = 0; + /* client data */ + public bool IsReady; + public byte[] PopBytes(int n) { var result = data.GetRange(0, n); diff --git a/OpenRA.Server/Server.cs b/OpenRA.Server/Server.cs index 188f415568..defb7c98b2 100644 --- a/OpenRA.Server/Server.cs +++ b/OpenRA.Server/Server.cs @@ -10,6 +10,55 @@ using System.Collections; namespace OpenRA.Server { + class ServerOrder + { + public readonly int PlayerId; + public readonly string Name; + public readonly string Data; + + public ServerOrder(int playerId, string name, string data) + { + PlayerId = playerId; + Name = name; + Data = data; + } + + public static ServerOrder Deserialize(BinaryReader r) + { + byte b; + switch (b = r.ReadByte()) + { + case 0xff: + Console.WriteLine("This isn't a server order."); + return null; + + case 0xfe: + { + var playerID = r.ReadInt32(); + var name = r.ReadString(); + var data = r.ReadString(); + + return new ServerOrder(playerID, name, data); + } + + default: + throw new NotImplementedException(b.ToString("x2")); + } + } + + public byte[] Serialize() + { + var ms = new MemoryStream(); + var bw = new BinaryWriter(ms); + + bw.Write((byte)0xfe); + bw.Write(PlayerId); + bw.Write(Name); + bw.Write(Data); + return ms.ToArray(); + } + } + static class Server { static List conns = new List(); @@ -27,10 +76,11 @@ namespace OpenRA.Server checkRead.Add(listener.Server); foreach (var c in conns) checkRead.Add(c.socket); - Socket.Select(checkRead, null, null, 1000000 /* 1s */); + /* msdn lies, -1 doesnt work. this is ~1h instead. */ + Socket.Select(checkRead, null, null, -2 ); - Console.WriteLine("Select() completed with {0} sockets", - checkRead.Count); + //Console.WriteLine("Select() completed with {0} sockets", + // checkRead.Count); foreach (Socket s in checkRead) if (s == listener.Server) AcceptConnection(); @@ -62,7 +112,7 @@ namespace OpenRA.Server { if (0 < (len = conn.socket.Receive(rx))) { - Console.WriteLine("Read {0} bytes", len); + // Console.WriteLine("Read {0} bytes", len); conn.data.AddRange(rx.Take(len)); } else @@ -81,8 +131,8 @@ namespace OpenRA.Server static void ReadData(Connection conn) { - Console.WriteLine("Start ReadData() for {0}", - conn.socket.RemoteEndPoint); + //Console.WriteLine("Start ReadData() for {0}", + // conn.socket.RemoteEndPoint); if (ReadDataInner(conn)) while (conn.data.Count >= conn.ExpectLength) @@ -106,8 +156,8 @@ namespace OpenRA.Server } } - Console.WriteLine("End ReadData() for {0}", - conn.socket.RemoteEndPoint); + //Console.WriteLine("End ReadData() for {0}", + // conn.socket.RemoteEndPoint); } static void DispatchOrders(Connection conn, int frame, byte[] data) @@ -125,13 +175,40 @@ namespace OpenRA.Server catch (Exception e) { DropClient(c, e); } } - if (frame == 0) - InterpretServerOrders(data); + if (frame == 0 && conn != null) + InterpretServerOrders(conn, data); } - static void InterpretServerOrders(byte[] data) + static void InterpretServerOrders(Connection conn, byte[] data) { - /* todo: handle all server orders! */ + var ms = new MemoryStream(data); + var br = new BinaryReader(ms); + + try + { + for (; ; ) + { + var so = ServerOrder.Deserialize(br); + if (so == null) return; + InterpretServerOrder(conn, so); + } + } + catch (EndOfStreamException) { } + } + + static void InterpretServerOrder(Connection conn, ServerOrder so) + { + switch (so.Name) + { + case "ToggleReady": + conn.IsReady ^= true; + + // start the game if everyone is ready. + if (conns.All(c => c.IsReady)) + DispatchOrders(null, 0, + new ServerOrder(0, "StartGame", "").Serialize()); + break; + } } static void DropClient(Connection c, Exception e) diff --git a/OpenRa.Game/Chrome.cs b/OpenRa.Game/Chrome.cs index 270ef53c6e..34edc7f9ef 100644 --- a/OpenRa.Game/Chrome.cs +++ b/OpenRa.Game/Chrome.cs @@ -86,13 +86,14 @@ namespace OpenRa.Game buildItems.Clear(); renderer.Device.DisableScissor(); - renderer.DrawText(string.Format("RenderFrame {0} ({2:F1} ms)\nTick {1} ({3:F1} ms)\n$ {4}\nPower {5}", + renderer.DrawText(string.Format("RenderFrame {0} ({2:F1} ms)\nTick {1} ({3:F1} ms)\n$ {4}\nPower {5}\nReady: {6}", Game.RenderFrame, Game.orderManager.FrameNumber, PerfHistory.items["render"].LastValue, PerfHistory.items["tick_time"].LastValue, Game.LocalPlayer.DisplayCash, - Game.LocalPlayer.GetTotalPower() + Game.LocalPlayer.GetTotalPower(), + Game.LocalPlayer.IsReady ? "Yes" : "No" ), new int2(140, 5), Color.White); PerfHistory.Render(renderer, Game.worldRenderer.lineRenderer); diff --git a/OpenRa.Game/MainWindow.cs b/OpenRa.Game/MainWindow.cs index 5adc13624c..2c608a8977 100755 --- a/OpenRa.Game/MainWindow.cs +++ b/OpenRa.Game/MainWindow.cs @@ -129,8 +129,13 @@ namespace OpenRa.Game base.OnKeyDown(e); /* hack hack hack */ - if (e.KeyCode == Keys.F8 && !Game.orderManager.GameStarted) - Game.orderManager.StartGame(); + if (e.KeyCode == Keys.F8) + { + Game.LocalPlayer.IsReady ^= true; + Game.controller.AddOrder( + new Order(Game.LocalPlayer, + "ToggleReady", null, null, int2.Zero, "") { IsImmediate = true }); + } } protected override void OnKeyPress(KeyPressEventArgs e) diff --git a/OpenRa.Game/Order.cs b/OpenRa.Game/Order.cs index c9f1fd8a22..21a50bfb92 100644 --- a/OpenRa.Game/Order.cs +++ b/OpenRa.Game/Order.cs @@ -17,7 +17,7 @@ namespace OpenRa.Game public readonly string TargetString; public bool IsImmediate; - Order(Player player, string orderString, Actor subject, + public Order(Player player, string orderString, Actor subject, Actor targetActor, int2 targetLocation, string targetString) { this.Player = player; @@ -30,6 +30,17 @@ namespace OpenRa.Game public byte[] Serialize() { + if (IsImmediate) /* chat, whatever */ + { + var ret = new MemoryStream(); + var w = new BinaryWriter(ret); + w.Write((byte)0xfe); + w.Write((uint)Player.Index); + w.Write(OrderString); + w.Write(TargetString); + return ret.ToArray(); + } + switch (OrderString) { // Format: @@ -56,6 +67,13 @@ namespace OpenRa.Game } } + static Player LookupPlayer(uint index) + { + return Game.players + .Where(x => x.Value.Index == index) + .First().Value; + } + public static Order Deserialize(BinaryReader r) { switch (r.ReadByte()) @@ -72,9 +90,21 @@ namespace OpenRa.Game if (r.ReadBoolean()) targetString = r.ReadString(); - var player = Game.players.Where( x => x.Value.Index == playerID ).First().Value; - return new Order( player, order, subject, targetActor, targetLocation, targetString); + return new Order( LookupPlayer(playerID), + order, subject, targetActor, targetLocation, + targetString); } + + case 0xfe: + { + var playerID = r.ReadUInt32(); + var name = r.ReadString(); + var data = r.ReadString(); + + return new Order(LookupPlayer(playerID), + name, null, null, int2.Zero, data); + } + default: throw new NotImplementedException(); } diff --git a/OpenRa.Game/Player.cs b/OpenRa.Game/Player.cs index 80bd86a7da..ce4b86b60f 100644 --- a/OpenRa.Game/Player.cs +++ b/OpenRa.Game/Player.cs @@ -15,6 +15,8 @@ namespace OpenRa.Game int powerProvided; int powerDrained; + public bool IsReady; + public Player( int index, int palette, string playerName, Race race ) { this.Index = index; diff --git a/OpenRa.Game/UnitOrders.cs b/OpenRa.Game/UnitOrders.cs index f8c723fcf6..f6be083700 100755 --- a/OpenRa.Game/UnitOrders.cs +++ b/OpenRa.Game/UnitOrders.cs @@ -97,6 +97,22 @@ namespace OpenRa.Game Game.chat.AddLine(Pair.New(order.Player.PlayerName + ":", order.TargetString)); break; } + case "ToggleReady": + { + Game.chat.AddLine(Pair.New(order.Player.PlayerName, "toggled ready status" )); + break; + } + case "AssignPlayer": + { + break; /* todo: set LocalPlayer based on this */ + } + case "StartGame": + { + Game.chat.AddLine(Pair.New("Server:", "The game has started.")); + Game.orderManager.StartGame(); + break; + } + default: throw new NotImplementedException(); }