/// <summary> /// Initializes a new instance of the <see cref="SharedObject" /> class. /// </summary> /// <param name="zOrderList">The z order list.</param> /// <param name="id">The identifier.</param> /// <param name="rectangle">The rectangle.</param> /// <param name="privateOwnerName">Name of the private owner.</param> /// <param name="gameElements">The game elements.</param> public SharedObject(List <SharedObject> zOrderList, int id, Rectangle rectangle, string privateOwnerName, List <GameElement> gameElements) { _zOrderList = zOrderList; Id = id; // Apply magnetic grid at creation: rectangle.Location = ScgGameState.GetMagneticLocation(rectangle); Rectangle = rectangle; GrabbedLocation = new Point(Rectangle.Left, Rectangle.Top); PrivateOwnerName = privateOwnerName; GameElements = gameElements; GrabberName = null; }
/// <summary> /// Registers the new client. /// </summary> /// <param name="clientName">Name of the client.</param> /// <param name="clientProtocolVersion"></param> public void RegisterClient(string clientName, int clientProtocolVersion) { if (!string.IsNullOrEmpty(clientName)) { try { var callback = OperationContext.Current.GetCallbackChannel<IScgBroadcastorCallBack>(); if (clientProtocolVersion != Common.ClientServerProtocolVersion) { callback.BroadcastBadProtocolVersion(Common.ClientServerProtocolVersion); return; } lock (ClientsLocker) { if (Clients.Count <= MaxClientCount) { lock (GameStateLocker) { LogInfo(string.Format("RegisterClient(clientName = '{0}')", clientName), 1); var removedPrivateAreaId = -1; //Remove the old client using the same name: if (Clients.Keys.Contains(clientName)) { // The new client uses an already registerd name. Refuse it: return; } //{ // Clients.Remove(clientName); // LogWarning(string.Format("_clients.Remove(clientName = '{0}')", clientName), 2); // // Remove the private area of the old client // removedPrivateAreaId = _gameState.RemovePrivateArea(clientName); // // Note: The removedSharedObjectId should be >= 0 // if (removedPrivateAreaId >= 0) // { // // Inform other existing clients of the disposed PrivateArea id: // foreach (var client in Clients) // { // // Prepare StateChangeEventDataType: // var stateChangeEventDataType = // new StateChangeEventDataType(); // stateChangeEventDataType.StateChangeEventType = // StateChangeEventType.DisposeSharedObject; // stateChangeEventDataType.SharedObjectId = removedPrivateAreaId; // // Send the StateChangeEventDataType to the client: // client.Value.ScgBroadcastorCallBack.BroadcastToClient( // stateChangeEventDataType); // LogInfo( // string.Format( // "BroadcastToClient'{0}'(DisposeSharedObject, removedPrivateAreaId = '{1}')", // client.Value.Name, removedPrivateAreaId), 3); // } // } //} Clients.Add(clientName, new Client(clientName, callback)); LogInfo(string.Format("_clients.Add(clientName = '{0}')", clientName), 4); if (Clients.Count == 1) { // Initialize a new game state _gameState = new ScgGameState(this); } bool newSharedObject; var privateArea = _gameState.CreatePrivateArea(clientName, out newSharedObject); // Search a possible client without private area (The registering client was previously already registered under another name we do not know) // WARNING: This now shouldn't occur since the registered clients will now hide the registering pane: foreach (var client in Clients) { if (_gameState.FindPrivateArea(client.Value.Name) == null) { var oldClientName = client.Value.Name; // Remove this orphan client corresponding to the old name of the registering client: Clients.Remove(oldClientName); LogWarning( string.Format("_clients.Remove(oldClientName = '{0}')", oldClientName), 5); // Inform other existing clients of the disposed PrivateArea id: foreach (var cli in Clients) { if (cli.Value.Name != clientName) { // Prepare StateChangeEventDataType: var stateChangeEventDataType = new StateChangeEventDataType(); stateChangeEventDataType.StateChangeEventType = StateChangeEventType.DisposeSharedObject; stateChangeEventDataType.PrivateOwnerClientName = oldClientName; stateChangeEventDataType.SharedObjectId = removedPrivateAreaId; // Send the StateChangeEventDataType to the client: cli.Value.ScgBroadcastorCallBack.BroadcastToClient( stateChangeEventDataType); LogInfo( string.Format( "BroadcastToClient'{0}'(DisposeSharedObject, removedPrivateAreaId = '{1}')", cli.Value.Name, removedPrivateAreaId), 6); } } break; } } // Inform other existing clients of new PrivateArea: foreach (var client in Clients) { if (client.Value.Name != clientName) { // Prepare StateChangeEventDataType: var stateChangeEventDataType = new StateChangeEventDataType(); stateChangeEventDataType.StateChangeEventType = StateChangeEventType.NewSharedObject; stateChangeEventDataType.SharedObjectId = privateArea.Id; stateChangeEventDataType.PrivateOwnerClientName = privateArea.PrivateOwnerName; stateChangeEventDataType.NewSharedObjectLocation = new Point(privateArea.Rectangle.Left, privateArea.Rectangle.Top); stateChangeEventDataType.SharedObjectSize = new Size(privateArea.Rectangle.Size.Width, privateArea.Rectangle.Size.Height); stateChangeEventDataType.NewSharedObjectPicture = privateArea.Picture; // Send the StateChangeEventDataType to the client: client.Value.ScgBroadcastorCallBack.BroadcastToClient(stateChangeEventDataType); LogInfo( string.Format( "BroadcastToClient'{0}'(NewSharedObject, privateArea.Id = '{1}')", client.Value.Name, privateArea.Id), 7); } } // Inform the new client (and only him) of the current state of the game: Client newClient; var foundNewClient = Clients.TryGetValue(clientName, out newClient); if (foundNewClient && newClient != null) { // Parse all shared objects in reversed order (from the back to the topmost one shared object): for (var i = _gameState.ZOrderListOfSharedObjects.Count - 1; i >= 0; i--) { var sharedObject = _gameState.ZOrderListOfSharedObjects[i]; // Prepare StateChangeEventDataType: var stateChangeEventDataType = new StateChangeEventDataType(); stateChangeEventDataType.StateChangeEventType = StateChangeEventType.NewSharedObject; stateChangeEventDataType.SharedObjectId = sharedObject.Id; stateChangeEventDataType.PrivateOwnerClientName = sharedObject.PrivateOwnerName; stateChangeEventDataType.NewSharedObjectLocation = new Point(sharedObject.Rectangle.Left, sharedObject.Rectangle.Top); stateChangeEventDataType.SharedObjectSize = new Size(sharedObject.Rectangle.Size.Width, sharedObject.Rectangle.Size.Height); stateChangeEventDataType.NewSharedObjectPicture = sharedObject.Picture; // Send the StateChangeEventDataType to the new (and only) client: newClient.ScgBroadcastorCallBack.BroadcastToClient(stateChangeEventDataType); LogInfo( string.Format( "BroadcastToClient'{0}'(NewSharedObject, sharedObject.Id = '{1}')", newClient, sharedObject.Id), 8); } } } } else { LogWarning( string.Format( "Refused to RegisterClient(clientName = '{0}') because the _clients list is full. ({1} clients)", clientName, Clients.Count), 1); } } } catch (Exception ex) { // Unexpected exception: LogWarning(string.Format("Unexpected exception ex.Message = '{0}' in RegisterClient)", ex.Message), 9); // Throw it to restart the service (in case of service channel canceled) throw; } } }