using System.Linq; using System.Collections.Generic; using System.Collections.Concurrent; using System.Threading.Tasks; using System.Net.Sockets; using UnityEngine; using Utilities; using System.Net; using System; using Empty = Google.Protobuf.WellKnownTypes.Empty; public class Client : MonoBehaviour { private static ConnectionImpl reference; public static void Connect(string name, string address = "127.0.0.1:50052") { reference = new ConnectionImpl(name, address); reference.eventManager.AddHandler("general_lobby_status_handler", (Lobby.LobbyStatus status) => { reference.lobby_status.Set(status); }); reference.eventManager.AddHandler("general_game_status_handler", (Game.GameStatus status) => { reference.game_status.Set(status); GameLoader.ReloadPiles(); }); } public static ref ConnectionImpl GetConnection() { return ref reference; } public static void CloseConnection() { if (reference != null) { reference.Close(); reference = null; } } void Update() { if (reference != null) { reference.eventManager.Update(); } } void OnApplicationQuit() { CloseConnection(); } public class NetEventManager { private Dictionary> returnNameHandlers = new Dictionary>(); private Dictionary> returnConnectHandlers = new Dictionary>(); private Dictionary> returnCreateLobbyHandlers = new Dictionary>(); private Dictionary> returnGamesHandlers = new Dictionary>(); private Dictionary> returnPublicLobbiesHandlers = new Dictionary>(); private Dictionary> returnUsersHandlers = new Dictionary>(); private Dictionary> lobbyStatusHandlers = new Dictionary>(); private Dictionary> returnCardImageHandlers = new Dictionary>(); private Dictionary> gameStatusHandlers = new Dictionary>(); public ConcurrentQueue queue; public void Update() { Protocol.ServerClientPacket p = null; while (queue.TryDequeue(out p)) { Debug.Log("Message " + p.DataCase); switch (p.DataCase) { case Protocol.ServerClientPacket.DataOneofCase.ReturnName: { var v = new Action[this.returnNameHandlers.Count]; this.returnNameHandlers.Values.CopyTo(v, 0); foreach (var n in v) { n(p.ReturnName); } } break; case Protocol.ServerClientPacket.DataOneofCase.ReturnConnect: { var v = new Action[this.returnConnectHandlers.Count]; this.returnConnectHandlers.Values.CopyTo(v, 0); foreach (var n in v) { n(p.ReturnConnect); } } break; case Protocol.ServerClientPacket.DataOneofCase.ReturnCreateLobby: { var v = new Action[this.returnCreateLobbyHandlers.Count]; this.returnCreateLobbyHandlers.Values.CopyTo(v, 0); foreach (var n in v) { n(p.ReturnCreateLobby); } } break; case Protocol.ServerClientPacket.DataOneofCase.ReturnGames: { var v = new Action[this.returnGamesHandlers.Count]; this.returnGamesHandlers.Values.CopyTo(v, 0); foreach (var n in v) { n(p.ReturnGames); } } break; case Protocol.ServerClientPacket.DataOneofCase.ReturnPublicLobbies: { var v = new Action[this.returnPublicLobbiesHandlers.Count]; this.returnPublicLobbiesHandlers.Values.CopyTo(v, 0); foreach (var n in v) { n(p.ReturnPublicLobbies); } } break; case Protocol.ServerClientPacket.DataOneofCase.ReturnUsers: { var v = new Action[this.returnUsersHandlers.Count]; this.returnUsersHandlers.Values.CopyTo(v, 0); foreach (var n in v) { n(p.ReturnUsers); } } break; case Protocol.ServerClientPacket.DataOneofCase.LobbyStatus: { var v = new Action[this.lobbyStatusHandlers.Count]; this.lobbyStatusHandlers.Values.CopyTo(v, 0); foreach (var n in v) { n(p.LobbyStatus); } } break; case Protocol.ServerClientPacket.DataOneofCase.ReturnCardImage: { var v = new Action[this.returnCardImageHandlers.Count]; this.returnCardImageHandlers.Values.CopyTo(v, 0); foreach (var n in v) { n(p.ReturnCardImage); } } break; case Protocol.ServerClientPacket.DataOneofCase.GameStatus: { var v = new Action[this.gameStatusHandlers.Count]; this.gameStatusHandlers.Values.CopyTo(v, 0); foreach (var n in v) { n(p.GameStatus); } } break; default: break; } } } public void AddHandler(string name, Action handler) { returnNameHandlers.Add(name, handler); } public void AddHandler(string name, Action handler) { returnConnectHandlers.Add(name, handler); } public void AddHandler(string name, Action handler) { returnCreateLobbyHandlers.Add(name, handler); } public void AddHandler(string name, Action handler) { returnGamesHandlers.Add(name, handler); } public void AddHandler(string name, Action handler) { returnPublicLobbiesHandlers.Add(name, handler); } public void AddHandler(string name, Action handler) { returnUsersHandlers.Add(name, handler); } public void AddHandler(string name, Action handler) { lobbyStatusHandlers.Add(name, handler); } public void AddHandler(string name, Action handler) { returnCardImageHandlers.Add(name, handler); } public void AddHandler(string name, Action handler) { gameStatusHandlers.Add(name, handler); } public void RemoveHandler(Protocol.ServerClientPacket.DataOneofCase kind, string name) { switch (kind) { case Protocol.ServerClientPacket.DataOneofCase.ReturnName: returnNameHandlers.Remove(name); break; case Protocol.ServerClientPacket.DataOneofCase.ReturnConnect: returnConnectHandlers.Remove(name); break; case Protocol.ServerClientPacket.DataOneofCase.ReturnCreateLobby: returnCreateLobbyHandlers.Remove(name); break; case Protocol.ServerClientPacket.DataOneofCase.ReturnGames: returnGamesHandlers.Remove(name); break; case Protocol.ServerClientPacket.DataOneofCase.ReturnPublicLobbies: returnPublicLobbiesHandlers.Remove(name); break; case Protocol.ServerClientPacket.DataOneofCase.ReturnUsers: returnUsersHandlers.Remove(name); break; case Protocol.ServerClientPacket.DataOneofCase.LobbyStatus: lobbyStatusHandlers.Remove(name); break; case Protocol.ServerClientPacket.DataOneofCase.ReturnCardImage: returnCardImageHandlers.Remove(name); break; case Protocol.ServerClientPacket.DataOneofCase.GameStatus: gameStatusHandlers.Remove(name); break; default: break; } } } public class ConnectionImpl // : MonoBehaviour { public TcpConnection conn; private string connId; private uint? lobby = null; private string address; public NetEventManager eventManager; public Modifiable lobby_status = new Modifiable(null); public Modifiable game_status = new Modifiable(null); public ConnectionImpl(string user, string address) { Debug.Log("Connecting with the tcp channel"); conn = new TcpConnection(address); conn.SendMessage(new Protocol.ClientServerPacket() { Connect = new Common.Name { Name_ = user } }); Protocol.ServerClientPacket p = null; Debug.Log("Waiting for response"); while (p == null) { conn.q.TryDequeue(out p); } if (p.ReturnConnect == null) { throw new Exception("Unexpected non ReturnConnect packet"); } connId = p.ReturnConnect.Id; this.address = address; this.eventManager = new NetEventManager() { queue = conn.q }; } public void QueryName() { conn.SendMessage(new Protocol.ClientServerPacket() { QueryName = new Google.Protobuf.WellKnownTypes.Empty() }); // return connection.name(new Google.Protobuf.WellKnownTypes.Empty()).Name_; } public string GetServerAddress() { return address; } public void JoinLobby(string code) { conn.SendMessage(new Protocol.ClientServerPacket() { JoinLobby = new Connection.LobbyCode { Code = Base32.FromString(code) } }); // connection.joinLobbyWithCode(new ConnectionService.LobbyCode { Code = (uint)lobby }, new Metadata { new Metadata.Entry("client_id", connId) }); } public void CreateLobby(bool isPublic) { eventManager.AddHandler("client_create_lobby_auto_join", (Connection.LobbyCode lobby1) => { lobby = lobby1.Code; eventManager.RemoveHandler(Protocol.ServerClientPacket.DataOneofCase.ReturnCreateLobby, "client_create_lobby_auto_join"); }); conn.SendMessage(new Protocol.ClientServerPacket() { CreateLobby = new Connection.LobbyConfig { Public = isPublic } }); // lobby = connection.createLobby(new ConnectionService.LobbyConfig {Public = isPublic}, new Metadata { new Metadata.Entry("client_id", connId) }).Code; } public string GetLobby() { if (lobby != null) { return Base32.ToString((uint)lobby); } else { return null; } } public void GetUsersInSameLobby() { conn.SendMessage(new Protocol.ClientServerPacket() { QueryUsers = new Empty() }); } public List GetLobbyVotes(uint game) { var gameVotes = new List(); if (lobby_status.Get() != null){ Google.Protobuf.Collections.RepeatedField votes = lobby_status.Get()?.Votes; foreach (Lobby.Vote vote in votes) { if (vote.Game == game) { gameVotes.Add(vote); } } } return gameVotes; } public int GetLobbyVoteCount(uint game) { var gameVotes = new List(); if (lobby_status.Get() != null) { Google.Protobuf.Collections.RepeatedField votes = lobby_status.Get()?.Votes; foreach (Lobby.Vote vote in votes) { if (vote.Game == game) { gameVotes.Add(vote); } } } return gameVotes.Count; } public Lobby.Vote GetSelfVote(string player) { if (lobby_status.Get() != null) { Google.Protobuf.Collections.RepeatedField votes = lobby_status.Get().Votes; foreach (Lobby.Vote vote in votes) { Debug.Log(vote); if (vote.Player == player) { return vote; } } } return null; } public bool IsStarting() { return lobby_status.Get() != null && lobby_status.Get().IsStarting; } public void Vote(uint game) { conn.SendMessage(new Protocol.ClientServerPacket() { Vote = new Lobby.SingleVote { Game = game } }); // lobby_client.vote(new Lobby.SingleVote() { Game = game }, new Metadata { new Metadata.Entry("client_id", connId) }); } public void SetReady() { conn.SendMessage(new Protocol.ClientServerPacket() { Ready = new Empty() }); // lobby_client.ready(new Google.Protobuf.WellKnownTypes.Empty(), new Metadata { new Metadata.Entry("client_id", connId) }); } public void LeaveLobby() { conn.SendMessage(new Protocol.ClientServerPacket() { Leave = new Empty() }); lobby = null; } public void GetPublicLobbies() { conn.SendMessage(new Protocol.ClientServerPacket() { QueryPublicLobbies = new Empty() }); } public void GetCardImage(string cardKind) { conn.SendMessage(new Protocol.ClientServerPacket() { QueryCardImage = new Game.CardKind { Kind = cardKind } }); } public int GetUserIndex(string user) { if (game_status.Get() != null) return game_status.Get().Names.IndexOf(new Common.Name { Name_ = user }); else return -1; } public Google.Protobuf.Collections.MapField GetPlayerPiles(string user) { int idx = this.GetUserIndex(user); if (idx != -1) { return game_status.Get().PlayerPiles[idx].Piles_; } return null; } public Google.Protobuf.Collections.MapField GetCommonPiles() { if (game_status.Get() != null) return game_status.Get().CommonPiles.Piles_; else return null; } public void OnClickCard(string pileName, bool isCommonPile, int cardIdx, string user) { Game.PileKind pileKind = new Game.PileKind() { Owned = (uint)GetUserIndex(user) }; if (isCommonPile) pileKind = new Game.PileKind { Common = new Empty() }; conn.SendMessage(new Protocol.ClientServerPacket() { CallOnClick = new Game.CardId { PileKind = pileKind, CardIndex = new Game.CardIndex { Index = (uint)cardIdx }, PileName = pileName } }); } // public Dictionary> OnClickCard(string pileName, bool isCommonPile, int cardIdx, string user) { // Game.PileKind pileKind = new Game.PileKind() { Owned = (uint)GetUserIndex(user) }; // game_client.onClick(new Game.CardId { PileKind = pileKind, CardIndex = new Game.CardIndex { Index = (uint)cardIdx }, PileName = pileName }, new Metadata { new Metadata.Entry("client_id", connId) }); // return GetPiles(user); // } public void GetGames() { conn.SendMessage(new Protocol.ClientServerPacket() { QueryGames = new Empty() }); } static T runSync(Task task) { task.Wait(); return task.Result; } public void Close() { conn.SendMessage(new Protocol.ClientServerPacket() {Disconnect = new Empty()}); } } }