/// <summary> /// Sends a <see cref = "JoinEvent" /> to all <see cref = "Actor" />s. /// </summary> /// <param name = "peer"> /// The peer. /// </param> /// <param name = "joinRequest"> /// The join request. /// </param> protected virtual void PublishJoinEvent(LitePeer peer, JoinRequest joinRequest) { Actor actor = this.GetActorByPeer(peer); if (actor == null) { return; } // generate a join event and publish to all actors in the room var joinEvent = new JoinEvent(actor.ActorNr, this.Actors.GetActorNumbers().ToArray()); if (joinRequest.BroadcastActorProperties) { joinEvent.ActorProperties = joinRequest.ActorProperties; } this.PublishEvent(joinEvent, this.Actors, new SendParameters()); }
/// <summary> /// Called for each operation in the execution queue. /// Every <see cref = "Room" /> has a queue of incoming operations to execute. /// Per game <see cref = "ExecuteOperation" /> is never executed multi-threaded, thus all code executed here has thread safe access to all instance members. /// </summary> /// <param name = "peer"> /// The peer. /// </param> /// <param name = "operationRequest"> /// The operation request to execute. /// </param> /// <param name = "sendParameters"> /// The send Parameters. /// </param> protected override void ExecuteOperation(LitePeer peer, OperationRequest operationRequest, SendParameters sendParameters) { try { base.ExecuteOperation(peer, operationRequest, sendParameters); if (Log.IsDebugEnabled) { Log.DebugFormat("Executing operation {0}", (OperationCode)operationRequest.OperationCode); } switch ((OperationCode)operationRequest.OperationCode) { case OperationCode.Join: { var joinRequest = new JoinRequest(peer.Protocol, operationRequest); if (peer.ValidateOperation(joinRequest, sendParameters) == false) { return; } this.logQueue.Add(new LogEntry("ExecuteOperation: " + (OperationCode)operationRequest.OperationCode, "Peer=" + peer.ConnectionId)); joinRequest.OnStart(); this.HandleJoinOperation(peer, joinRequest, sendParameters); joinRequest.OnComplete(); break; } case OperationCode.Leave: { var leaveOperation = new LeaveRequest(peer.Protocol, operationRequest); if (peer.ValidateOperation(leaveOperation, sendParameters) == false) { return; } this.logQueue.Add(new LogEntry("ExecuteOperation: " + (OperationCode)operationRequest.OperationCode, "Peer=" + peer.ConnectionId)); leaveOperation.OnStart(); this.HandleLeaveOperation(peer, leaveOperation, sendParameters); leaveOperation.OnComplete(); break; } case OperationCode.RaiseEvent: { var raiseEventOperation = new RaiseEventRequest(peer.Protocol, operationRequest); if (peer.ValidateOperation(raiseEventOperation, sendParameters) == false) { return; } raiseEventOperation.OnStart(); this.HandleRaiseEventOperation(peer, raiseEventOperation, sendParameters); raiseEventOperation.OnComplete(); break; } case OperationCode.GetProperties: { var getPropertiesOperation = new GetPropertiesRequest(peer.Protocol, operationRequest); if (peer.ValidateOperation(getPropertiesOperation, sendParameters) == false) { return; } getPropertiesOperation.OnStart(); this.HandleGetPropertiesOperation(peer, getPropertiesOperation, sendParameters); getPropertiesOperation.OnComplete(); break; } case OperationCode.SetProperties: { var setPropertiesOperation = new SetPropertiesRequest(peer.Protocol, operationRequest); if (peer.ValidateOperation(setPropertiesOperation, sendParameters) == false) { return; } setPropertiesOperation.OnStart(); this.HandleSetPropertiesOperation(peer, setPropertiesOperation, sendParameters); setPropertiesOperation.OnComplete(); break; } case OperationCode.Ping: { peer.SendOperationResponse(new OperationResponse { OperationCode = operationRequest.OperationCode }, sendParameters); break; } default: { string message = string.Format("Unknown operation code {0}", (OperationCode)operationRequest.OperationCode); peer.SendOperationResponse( new OperationResponse { OperationCode = operationRequest.OperationCode, ReturnCode = -1, DebugMessage = message }, sendParameters); if (Log.IsWarnEnabled) { Log.Warn(message); } } break; } } catch (Exception ex) { Log.Error(ex); } }
/// <summary> /// Handles the <see cref = "JoinRequest" />: Joins a peer to a room and calls <see cref = "PublishJoinEvent" />. /// Before a JoinOperation reaches this point (inside a room), the <see cref = "LitePeer" /> made /// sure that it is removed from the previous Room (if there was any). /// </summary> /// <param name = "peer"> /// The peer. /// </param> /// <param name = "joinRequest"> /// The join operation. /// </param> /// <param name = "sendParameters"> /// The send Parameters. /// </param> /// <returns> /// The newly created (joined) actor or null if the peer already joined. /// </returns> protected virtual Actor HandleJoinOperation(LitePeer peer, JoinRequest joinRequest, SendParameters sendParameters) { if (this.IsDisposed) { // join arrived after being disposed - repeat join operation if (Log.IsWarnEnabled) { Log.WarnFormat("Join operation on disposed game. GameName={0}", this.Name); } return null; } if (Log.IsDebugEnabled) { Log.DebugFormat("Join operation from IP: {0} to port: {1}", peer.RemoteIP, peer.LocalPort); } // create an new actor Actor actor; if (this.TryAddPeerToGame(peer, out actor) == false) { peer.SendOperationResponse( new OperationResponse { OperationCode = joinRequest.OperationRequest.OperationCode, ReturnCode = -1, DebugMessage = "Peer already joined the specified game." }, sendParameters); return null; } // set game properties for join from the first actor if (this.Actors.Count == 1) { this.DeleteCacheOnLeave = joinRequest.DeleteCacheOnLeave; if (joinRequest.GameProperties != null) { this.Properties.SetProperties(joinRequest.GameProperties); } } // set custom actor properties if defined if (joinRequest.ActorProperties != null) { actor.Properties.SetProperties(joinRequest.ActorProperties); } // set operation return values and publish the response var joinResponse = new JoinResponse { ActorNr = actor.ActorNr }; if (this.Properties.Count > 0) { joinResponse.CurrentGameProperties = this.Properties.GetProperties(); } foreach (Actor t in this.Actors) { if (t.ActorNr != actor.ActorNr && t.Properties.Count > 0) { if (joinResponse.CurrentActorProperties == null) { joinResponse.CurrentActorProperties = new Hashtable(); } Hashtable actorProperties = t.Properties.GetProperties(); joinResponse.CurrentActorProperties.Add(t.ActorNr, actorProperties); } } peer.SendOperationResponse(new OperationResponse(joinRequest.OperationRequest.OperationCode, joinResponse), sendParameters); // publish join event this.PublishJoinEvent(peer, joinRequest); this.PublishEventCache(peer); return actor; }
/// <summary> /// Called by <see cref = "HandleJoinOperation" /> to get a room reference for a join operations. /// This method can be overloaded by inheritors to provide custom room references. /// </summary> /// <param name = "joinRequest">The join request.</param> /// <returns>An <see cref = "Caching.RoomReference" /> instance.</returns> protected virtual RoomReference GetRoomReference(JoinRequest joinRequest) { return LiteGameCache.Instance.GetRoomReference(joinRequest.GameId, this); }
/// <summary> /// Handles the <see cref = "JoinRequest" /> to enter a <see cref = "LiteGame" />. /// This method removes the peer from any previously joined room, finds the room intended for join /// and enqueues the operation for it to handle. /// </summary> /// <param name = "operationRequest"> /// The operation request to handle. /// </param> /// <param name = "sendParameters"> /// The send Parameters. /// </param> protected virtual void HandleJoinOperation(OperationRequest operationRequest, SendParameters sendParameters) { // create join operation var joinRequest = new JoinRequest(this.Protocol, operationRequest); if (this.ValidateOperation(joinRequest, sendParameters) == false) { return; } // remove peer from current game this.RemovePeerFromCurrentRoom(); // get a game reference from the game cache // the game will be created by the cache if it does not exists already RoomReference gameReference = this.GetRoomReference(joinRequest); // save the game reference in the peers state this.RoomReference = gameReference; // finally enqueue the operation into game queue gameReference.Room.EnqueueOperation(this, operationRequest, sendParameters); }
/// <summary> /// Updates the lobby when an <see cref = "Actor" /> joins. /// </summary> /// <param name = "peer"> /// The peer. /// </param> /// <param name = "joinRequest"> /// The join operation. /// </param> /// <param name = "sendParamters"> /// The send Paramters. /// </param> /// <returns> /// The newly created (joined) <see cref = "Actor" />. /// </returns> protected override Actor HandleJoinOperation(LitePeer peer, JoinRequest joinRequest, SendParameters sendParamters) { Actor actor = base.HandleJoinOperation(peer, joinRequest, sendParamters); if (actor != null) { this.UpdateLobby(); } return actor; }
protected override RoomReference GetRoomReference(JoinRequest joinRequest) { return MyGameCache.Instance.GetRoomReference(joinRequest.GameId, this); }
protected override RoomReference GetRoomReference(JoinRequest joinRequest) { throw new NotSupportedException("Use TryGetRoomReference or TryCreateRoomReference instead."); }
protected override void ExecuteOperation(LitePeer peer, OperationRequest operationRequest, SendParameters sendParameters) { try { if (Log.IsDebugEnabled) { Log.DebugFormat("Executing operation {0}", operationRequest.OperationCode); } switch (operationRequest.OperationCode) { case (byte)OperationCode.CreateGame: var createGameRequest = new JoinGameRequest(peer.Protocol, operationRequest); if (peer.ValidateOperation(createGameRequest, sendParameters) == false) { return; } if (this.LogQueue.Log.IsDebugEnabled) { this.LogQueue.Add( new LogEntry( "ExecuteOperation: " + (OperationCode)operationRequest.OperationCode, "Peer=" + peer.ConnectionId)); } this.HandleCreateGameOperation(peer, createGameRequest, sendParameters); break; case (byte)OperationCode.JoinGame: var joinGameRequest = new JoinRequest(peer.Protocol, operationRequest); if (peer.ValidateOperation(joinGameRequest, sendParameters) == false) { return; } if (this.LogQueue.Log.IsDebugEnabled) { this.LogQueue.Add( new LogEntry( "ExecuteOperation: " + (OperationCode)operationRequest.OperationCode, "Peer=" + peer.ConnectionId)); } this.HandleJoinGameOperation(peer, joinGameRequest, sendParameters); break; // Lite operation code for join is not allowed in load balanced games. case (byte)Lite.Operations.OperationCode.Join: var response = new OperationResponse { OperationCode = operationRequest.OperationCode, ReturnCode = (short)ErrorCode.OperationDenied, DebugMessage = "Invalid operation code" }; peer.SendOperationResponse(response, sendParameters); break; case (byte)OperationCode.DebugGame: var debugGameRequest = new DebugGameRequest(peer.Protocol, operationRequest); if (peer.ValidateOperation(debugGameRequest, sendParameters) == false) { return; } if (this.LogQueue.Log.IsDebugEnabled) { this.LogQueue.Add( new LogEntry( "ExecuteOperation: " + (OperationCode)operationRequest.OperationCode, "Peer=" + peer.ConnectionId)); } this.HandleDebugGameOperation(peer, debugGameRequest, sendParameters); break; // all other operation codes will be handled by the Lite game implementation default: base.ExecuteOperation(peer, operationRequest, sendParameters); break; } } catch (Exception ex) { Log.Error(ex); } }
protected virtual Actor HandleJoinGameOperation(LitePeer peer, JoinRequest joinRequest, SendParameters sendParameters) { if (!this.ValidateGame(peer, joinRequest.OperationRequest, sendParameters)) { return null; } // special treatment for game and actor properties sent by AS3/Flash var protocol = peer.Protocol.ProtocolType; if (protocol == ProtocolType.Amf3V152 || protocol == ProtocolType.Json) { Utilities.ConvertAs3WellKnownPropertyKeys(joinRequest.GameProperties, joinRequest.ActorProperties); } var gamePeer = (GameClientPeer)peer; Actor actor = this.HandleJoinOperation(peer, joinRequest, sendParameters); if (actor == null) { return null; } // update game state at master server var peerId = gamePeer.PeerId ?? string.Empty; this.UpdateGameStateOnMaster(null, null, null, null, joinRequest.GameProperties, peerId); return actor; }
protected virtual Actor HandleJoinGameOperation(LitePeer peer, JoinRequest joinRequest, SendParameters sendParameters) { if (!this.ValidateGame(peer, joinRequest.OperationRequest, sendParameters)) { return null; } var gamePeer = (GameClientPeer)peer; var baseRequest = new JoinRequest(peer.Protocol, joinRequest.OperationRequest); Actor actor = this.HandleJoinOperation(peer, baseRequest, sendParameters); if (actor == null) { return null; } // update game state at master server var peerId = gamePeer.PeerId ?? string.Empty; this.UpdateGameStateOnMaster(joinRequest.GameProperties, peerId, null, false); return actor; }
protected virtual Actor HandleCreateGameOperation(LitePeer peer, JoinRequest createRequest, SendParameters sendParameters) { if (!this.ValidateGame(peer, createRequest.OperationRequest, sendParameters)) { return null; } var gamePeer = (GameClientPeer)peer; byte? newMaxPlayer = null; bool? newIsOpen = null; bool? newIsVisible = null; object[] newLobbyProperties = null; // try to parse build in properties for the first actor (creator of the game) if (this.Actors.Count == 0) { if (createRequest.GameProperties != null && createRequest.GameProperties.Count > 0) { if (!TryParseDefaultProperties(peer, createRequest, createRequest.GameProperties, sendParameters, out newMaxPlayer, out newIsOpen, out newIsVisible, out newLobbyProperties)) { return null; } } } var baseRequest = new JoinRequest(peer.Protocol, createRequest.OperationRequest); Actor actor = this.HandleJoinOperation(peer, baseRequest, sendParameters); if (actor == null) { return null; } // set default properties if (newMaxPlayer.HasValue && newMaxPlayer.Value != this.maxPlayers) { this.maxPlayers = newMaxPlayer.Value; } if (newIsOpen.HasValue && newIsOpen.Value != this.isOpen) { this.isOpen = newIsOpen.Value; } if (newIsVisible.HasValue && newIsVisible.Value != this.isVisible) { this.isVisible = newIsVisible.Value; } if (newLobbyProperties != null) { this.lobbyProperties = new HashSet<object>(newLobbyProperties); } Hashtable gameProperties; if (this.lobbyProperties == null) { // if no filter is set for properties which should be listet in the lobby // all properties are send gameProperties = this.Properties.GetProperties(); } else { // filter for game properties is set, only properties in the specified list // will be reported to the lobby gameProperties = new Hashtable(); // build in properties are always sent to the master server after creating a new game gameProperties.Add((byte)GameParameter.MaxPlayer, this.maxPlayers); gameProperties.Add((byte)GameParameter.IsVisible, this.isVisible); gameProperties.Add((byte)GameParameter.IsOpen, this.isOpen); gameProperties.Add((byte)GameParameter.Properties, newLobbyProperties); foreach (var key in this.lobbyProperties) { var prop = this.Properties.GetProperty(key); if (prop != null) { gameProperties[key] = prop.Value; } } } // update game state at master server var peerId = gamePeer.PeerId ?? string.Empty; this.UpdateGameStateOnMaster(gameProperties, peerId, null, false); return actor; }