/// <summary> /// Removes a peer from the game. /// This method is called if a client sends a <see cref = "LeaveRequest" /> or disconnects. /// </summary> /// <param name = "peer"> /// The <see cref = "LitePeer" /> to remove. /// </param> /// <param name="leaveRequest"> /// The <see cref="LeaveRequest"/> sent by the peer or null if the peer have been disconnected without sending a leave request. /// </param> /// <returns> /// The actor number of the removed actor. /// If the specified peer does not exists -1 will be returned. /// </returns> protected virtual int RemovePeerFromGame(LitePeer peer, LeaveRequest leaveRequest) { Actor actor = this.Actors.RemoveActorByPeer(peer); if (actor == null) { if (Log.IsWarnEnabled) { Log.WarnFormat("RemovePeerFromGame - Actor to remove not found for peer: {0}", peer.ConnectionId); } return(-1); } this.actorEventCache.RemoveEventCache(actor.ActorNr); if (this.DeleteCacheOnLeave) { this.eventCache.RemoveEventsByActor(actor.ActorNr); } // raise leave event this.PublishLeaveEvent(actor, leaveRequest); return(actor.ActorNr); }
/// <summary> /// Removes a peer from the game. /// This method is called if a client sends a <see cref = "LeaveRequest" /> or disconnects. /// </summary> /// <param name = "peer"> /// The <see cref = "LitePeer" /> to remove. /// </param> /// <returns> /// The actor number of the removed actor. /// If the specified peer does not exists -1 will be returned. /// </returns> protected virtual int RemovePeerFromGame(LitePeer peer) { Actor actor = this.Actors.RemoveActorByPeer(peer); if (actor == null) { if (Log.IsWarnEnabled) { Log.WarnFormat("RemovePeerFromGame - Actor to remove not found for peer: {0}", peer.ConnectionId); } return(-1); } this.cachedEvents.Remove(actor.ActorNr); // raise leave event if (this.Actors.Count > 0) { IEnumerable <int> actorNumbers = this.Actors.GetActorNumbers(); var leaveEvent = new LeaveEvent(actor.ActorNr, actorNumbers.ToArray()); this.PublishEvent(leaveEvent, this.Actors, new SendParameters()); } return(actor.ActorNr); }
/// <summary> /// Sends all cached events to a peer. /// </summary> /// <param name = "litePeer"> /// The lite peer that receives the events. /// </param> protected void PublishEventCache(LitePeer litePeer) { var @event = new CustomEvent(0, 0, null); foreach (KeyValuePair <int, EventCache> entry in this.actorEventCache) { int actor = entry.Key; EventCache cache = entry.Value; @event.ActorNr = actor; foreach (KeyValuePair <byte, Hashtable> eventEntry in cache) { @event.Code = @eventEntry.Key; @event.Data = @eventEntry.Value; var eventData = new EventData(@event.Code, @event); litePeer.SendEvent(eventData, new SendParameters()); } } foreach (CustomEvent customEvent in this.eventCache) { var eventData = new EventData(customEvent.Code, customEvent); litePeer.SendEvent(eventData, new SendParameters()); } }
/// <summary> /// Handles the <see cref = "SetPropertiesRequest" /> and sends event <see cref = "PropertiesChangedEvent" /> to all <see cref = "Actor" />s in the room. /// </summary> /// <param name = "peer"> /// The peer. /// </param> /// <param name = "setPropertiesRequest"> /// The <see cref = "SetPropertiesRequest" /> operation to handle. /// </param> /// <param name = "sendParameters"> /// The send Parameters. /// </param> protected virtual void HandleSetPropertiesOperation(LitePeer peer, SetPropertiesRequest setPropertiesRequest, SendParameters sendParameters) { // check if peer has joined this room instance var sender = this.GetActorByPeer(peer); if (sender == null) { var response = new OperationResponse { OperationCode = setPropertiesRequest.OperationRequest.OperationCode, ReturnCode = -1, DebugMessage = "Room not joined" }; peer.SendOperationResponse(response, sendParameters); return; } if (setPropertiesRequest.ActorNumber > 0) { Actor actor = this.Actors.GetActorByNumber(setPropertiesRequest.ActorNumber); if (actor == null) { peer.SendOperationResponse( new OperationResponse { OperationCode = setPropertiesRequest.OperationRequest.OperationCode, ReturnCode = -1, DebugMessage = string.Format("Actor with number {0} not found.", setPropertiesRequest.ActorNumber) }, sendParameters); return; } actor.Properties.SetProperties(setPropertiesRequest.Properties); } else { this.Properties.SetProperties(setPropertiesRequest.Properties); } peer.SendOperationResponse(new OperationResponse { OperationCode = setPropertiesRequest.OperationRequest.OperationCode }, sendParameters); // if the optional paramter Broadcast is set a EvPropertiesChanged // event will be send to room actors if (setPropertiesRequest.Broadcast) { Actor actor = this.Actors.GetActorByPeer(peer); IEnumerable <Actor> recipients = this.Actors.GetExcludedList(actor); var propertiesChangedEvent = new PropertiesChangedEvent(actor.ActorNr) { TargetActorNumber = setPropertiesRequest.ActorNumber, Properties = setPropertiesRequest.Properties }; this.PublishEvent(propertiesChangedEvent, recipients, sendParameters); } }
/// <summary> /// Handles the <see cref = "LeaveRequest" /> and calls <see cref = "RemovePeerFromGame" />. /// </summary> /// <param name = "peer"> /// The peer. /// </param> /// <param name = "leaveRequest"> /// The operation. /// </param> /// <param name = "sendParameters"> /// The send Parameters. /// </param> protected virtual void HandleLeaveOperation(LitePeer peer, LeaveRequest leaveRequest, SendParameters sendParameters) { this.RemovePeerFromGame(peer, leaveRequest); // is always reliable, so it gets a response peer.SendOperationResponse(new OperationResponse { OperationCode = leaveRequest.OperationRequest.OperationCode }, sendParameters); }
private void DebugLog(LitePeer peer, OperationRequest operationRequest) { if (this.LogQueue.Log.IsDebugEnabled) { this.LogQueue.Add( new LogEntry( "ExecuteOperation: " + (Lite.Operations.OperationCode)operationRequest.OperationCode, "Peer=" + peer.ConnectionId)); } }
private void HandleMyGameOperation(LitePeer peer, OperationRequest operationRequest, SendParameters sendParameters) { var requestContract = new MyGameRequest(peer.Protocol, operationRequest); requestContract.OnStart(); var responseContract = new MyGameResponse(); responseContract.Response = "You are in game " + this.Name; var operationResponse = new OperationResponse(operationRequest.OperationCode, responseContract); peer.SendOperationResponse(operationResponse, sendParameters); requestContract.OnComplete(); }
/// <summary> /// Sends a <see cref = "LeaveEvent" /> to all <see cref = "Actor" />s. /// </summary> /// <param name = "peer"> /// The peer. /// </param> /// <param name = "leaveRequest"> /// The leave operation. /// </param> protected virtual void PublishLeaveEvent(LitePeer peer, LeaveRequest leaveRequest) { if (this.Actors.Count > 0) { Actor actor = this.GetActorByPeer(peer); if (actor != null) { IEnumerable <int> actorNumbers = this.Actors.GetActorNumbers(); var leaveEvent = new LeaveEvent(actor.ActorNr, actorNumbers.ToArray()); this.PublishEvent(leaveEvent, this.Actors, new SendParameters()); } } }
private void HandleLeaveOperation(LitePeer peer, OperationRequest operationRequest, SendParameters sendParameters) { var leaveOperation = new LeaveRequest(peer.Protocol, operationRequest); if (peer.ValidateOperation(leaveOperation, sendParameters) == false) { return; } DebugLog(peer, operationRequest); leaveOperation.OnStart(); this.HandleLeaveOperation(peer, leaveOperation, sendParameters); leaveOperation.OnComplete(); }
/// <summary> /// Gets the actor for a <see cref = "LitePeer" />. /// </summary> /// <param name = "peer"> /// The peer. /// </param> /// <returns> /// The actor for the peer or null if no actor for the peer exists (this should not happen). /// </returns> protected Actor GetActorByPeer(LitePeer peer) { Actor actor = this.Actors.GetActorByPeer(peer); if (actor == null) { if (Log.IsDebugEnabled) { Log.DebugFormat("Actor not found for peer: {0}", peer.ConnectionId); } } return(actor); }
/// <summary> /// Called for each operation in the execution queue. /// </summary> /// <param name="peer">The peer.</param> /// <param name="operationRequest">The operation request to execute.</param> /// <param name="sendParameters"></param> /// <remarks> /// ExecuteOperation is overriden to handle our custom operations. /// </remarks> protected override void ExecuteOperation(LitePeer peer, OperationRequest operationRequest, SendParameters sendParameters) { switch ((MyOperationCodes)operationRequest.OperationCode) { case MyOperationCodes.GameOperation: this.HandleMyGameOperation(peer, operationRequest, sendParameters); break; default: // all other operations will be handled by the LiteGame implementation base.ExecuteOperation(peer, operationRequest, sendParameters); break; } }
/// <summary> /// Removes the actor for a a specified peer. /// </summary> /// <param name="peer"> /// The peer. /// </param> /// <returns> /// The <see cref="Actor"/> removed or <c>null</c> if no actor for the specified peer exists. /// </returns> public Actor RemoveActorByPeer(LitePeer peer) { int index = this.FindIndex(actor => actor.Peer == peer); if (index == -1) { return(null); } Actor result = this[index]; this.RemoveAt(index); return(result); }
/// <summary> /// Dispatches the <see cref="JoinRequest"/> different from the base <see cref="LiteGame.ExecuteOperation">LiteGame.ExecuteOperation</see>. /// </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) { switch ((OperationCode)operationRequest.OperationCode) { case OperationCode.Join: var joinOperation = new JoinRequest(peer.Protocol, operationRequest); if (peer.ValidateOperation(joinOperation, sendParameters) == false) { return; } this.HandleJoinOperation(peer, joinOperation, sendParameters); return; } base.ExecuteOperation(peer, operationRequest, sendParameters); }
protected override void ExecuteOperation(LitePeer peer, OperationRequest operationRequest, SendParameters sendParameters) { switch (operationRequest.OperationCode) { case (byte) DiscussionOpCode.NotifyLeaveUser: { broadcastNewInLobby(); break; } default: base.ExecuteOperation(peer, operationRequest, sendParameters); break; } base.ExecuteOperation(peer, operationRequest, sendParameters); }
/// <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> /// Handles the <see cref = "GetPropertiesRequest" /> operation: Sends the properties with the <see cref = "OperationResponse" />. /// </summary> /// <param name = "peer"> /// The peer. /// </param> /// <param name = "getPropertiesRequest"> /// The operation to handle. /// </param> /// <param name = "sendParameters"> /// The send Parameters. /// </param> protected virtual void HandleGetPropertiesOperation(LitePeer peer, GetPropertiesRequest getPropertiesRequest, SendParameters sendParameters) { var response = new GetPropertiesResponse(); // check if game properties should be returned if ((getPropertiesRequest.PropertyType & (byte)PropertyType.Game) == (byte)PropertyType.Game) { response.GameProperties = this.Properties.GetProperties(getPropertiesRequest.GamePropertyKeys); } // check if actor properties should be returned if ((getPropertiesRequest.PropertyType & (byte)PropertyType.Actor) == (byte)PropertyType.Actor) { response.ActorProperties = new Hashtable(); if (getPropertiesRequest.ActorNumbers == null) { foreach (Actor actor in this.Actors) { Hashtable actorProperties = actor.Properties.GetProperties(getPropertiesRequest.ActorPropertyKeys); response.ActorProperties.Add(actor.ActorNr, actorProperties); } } else { foreach (int actorNumber in getPropertiesRequest.ActorNumbers) { Actor actor = this.Actors.GetActorByNumber(actorNumber); if (actor != null) { Hashtable actorProperties = actor.Properties.GetProperties(getPropertiesRequest.ActorPropertyKeys); response.ActorProperties.Add(actorNumber, actorProperties); } } } } peer.SendOperationResponse( new OperationResponse(getPropertiesRequest.OperationRequest.OperationCode, response), sendParameters); }
public void AllRoomsBroadcast(LitePeer peer, OperationRequest operationRequest, SendParameters sendParameters, byte EventCode) { foreach (string roomName in roomList) { RoomReference rr = DiscussionGameCache.Instance.GetRoomReference(roomName); DiscussionRoom discussionRoom = rr.Room as DiscussionRoom; if (discussionRoom != null) { discussionRoom.Broadcast(peer, operationRequest, sendParameters, EventCode, BroadcastTo.RoomAll); } } BroadcastLobby(operationRequest, sendParameters, EventCode); }
/// <summary> /// Tries to add a <see cref = "LitePeer" /> to this game instance. /// </summary> /// <param name = "peer"> /// The peer to add. /// </param> /// <param name = "actor"> /// When this method returns this out param contains the <see cref = "Actor" /> associated with the <paramref name = "peer" />. /// </param> /// <returns> /// Returns true if no actor exists for the specified peer and a new actor for the peer has been successfully added. /// The actor parameter is set to the newly created <see cref = "Actor" /> instance. /// Returns false if an actor for the specified peer already exists. /// The actor paramter is set to the existing <see cref = "Actor" /> for the specified peer. /// </returns> protected virtual bool TryAddPeerToGame(LitePeer peer, out Actor actor) { // check if the peer already exists in this game actor = this.Actors.GetActorByPeer(peer); if (actor != null) { return(false); } // create new actor instance actor = new Actor(peer); this.actorNumberCounter++; actor.ActorNr = this.actorNumberCounter; this.Actors.Add(actor); if (Log.IsDebugEnabled) { Log.DebugFormat("Actor added: {0} to game: {1}", actor.ActorNr, this.Name); } return(true); }
protected override void ExecuteOperation(LitePeer peer, OperationRequest operationRequest, SendParameters sendParameters) { try { if (Log.IsDebugEnabled) { Log.DebugFormat("Executing operation {0}", operationRequest.OperationCode); } switch ((byte)operationRequest.OperationCode) { case (byte)SPOperationCode.Leave: HandleLeaveOperation(peer, operationRequest, sendParameters); break; //case (byte)SPServer.Operations.SPOperationCode.UpdateFlightControls: //HandleUpdateFlightControls(peer, operationRequest, sendParameters); //break; // Block non-authoritative Lite op codes. case (byte)Lite.Operations.OperationCode.RaiseEvent: case (byte)Lite.Operations.OperationCode.GetProperties: case (byte)Lite.Operations.OperationCode.SetProperties: case (byte)Lite.Operations.OperationCode.ChangeGroups: HandleLiteOperations(peer, operationRequest, sendParameters); break; // all other operation codes will be handled by the LoadBalancing Game implementation default: base.ExecuteOperation(peer, operationRequest, sendParameters); break; } } catch (Exception ex) { Log.Error(ex); } }
protected virtual void HandleChangeGroupsOperation(LitePeer peer, ChangeGroups changeGroupsRequest, SendParameters sendParameters) { // get the actor who send the operation request Actor actor = this.GetActorByPeer(peer); if (actor == null) { return; } actor.RemoveGroups(changeGroupsRequest.Remove); if (changeGroupsRequest.Add != null) { if (changeGroupsRequest.Add.Length > 0) { foreach (var groupId in changeGroupsRequest.Add) { ActorGroup group; if (!this.actorGroups.TryGetValue(groupId, out group)) { group = new ActorGroup(groupId); this.actorGroups.Add(groupId, group); } actor.AddGroup(group); } } else { foreach (var group in this.actorGroups.Values) { actor.AddGroup(group); } } } }
/// <summary> /// Handles the <see cref = "RaiseEventRequest" />: Sends a <see cref = "CustomEvent" /> to actors in the room. /// </summary> /// <param name = "peer"> /// The peer. /// </param> /// <param name = "raiseEventRequest"> /// The operation /// </param> /// <param name = "sendParameters"> /// The send Parameters. /// </param> protected virtual void HandleRaiseEventOperation(LitePeer peer, RaiseEventRequest raiseEventRequest, SendParameters sendParameters) { // get the actor who send the operation request Actor actor = this.GetActorByPeer(peer); if (actor == null) { return; } var customEvent = new CustomEvent(actor.ActorNr, raiseEventRequest.EvCode, raiseEventRequest.Data); if (raiseEventRequest.Cache == (byte) CacheOperation.RemoveFromRoomCache) { this.roomEventCache.RemoveEvents(raiseEventRequest); var response = new OperationResponse(raiseEventRequest.OperationRequest.OperationCode) {ReturnCode = 0}; peer.SendOperationResponse(response, sendParameters); return; } // publish the custom event IEnumerable<Actor> recipients; if (raiseEventRequest.Actors != null && raiseEventRequest.Actors.Length > 0) { recipients = this.Actors.GetActorsByNumbers(raiseEventRequest.Actors); sendParameters.Flush = raiseEventRequest.Flush; this.PublishEvent(customEvent, recipients, sendParameters); return; } switch (raiseEventRequest.ReceiverGroup) { case (byte) ReceiverGroup.All: { recipients = this.Actors; if (raiseEventRequest.Cache == (byte) CacheOperation.AddToRoomCache) { customEvent.Cache = raiseEventRequest.Cache; this.roomEventCache.AddEvent(customEvent); } else if (raiseEventRequest.Cache == (byte) CacheOperation.AddToRoomCacheGlobal) { customEvent.ActorNr = 0; customEvent.Cache = raiseEventRequest.Cache; this.roomEventCache.AddEvent(customEvent); } else if (raiseEventRequest.Cache != (byte) CacheOperation.DoNotCache) { if (!this.UpdateEventCache(actor, raiseEventRequest, raiseEventRequest.EvCode)) { peer.SendOperationResponse( new OperationResponse { OperationCode = raiseEventRequest.OperationRequest.OperationCode, ReturnCode = -1, DebugMessage = "Invalid cache operation " + raiseEventRequest.Cache }, sendParameters); return; } customEvent.Cache = raiseEventRequest.Cache; } break; } case (byte) ReceiverGroup.Others: { recipients = this.Actors.GetExcludedList(actor); if (raiseEventRequest.Cache == (byte) CacheOperation.AddToRoomCache) { customEvent.Cache = raiseEventRequest.Cache; this.roomEventCache.AddEvent(customEvent); } else if (raiseEventRequest.Cache == (byte) CacheOperation.AddToRoomCacheGlobal) { customEvent.ActorNr = 0; customEvent.Cache = raiseEventRequest.Cache; this.roomEventCache.AddEvent(customEvent); } else if (raiseEventRequest.Cache != (byte) CacheOperation.DoNotCache) { if (!this.UpdateEventCache(actor, raiseEventRequest, raiseEventRequest.EvCode)) { peer.SendOperationResponse( new OperationResponse { OperationCode = raiseEventRequest.OperationRequest.OperationCode, ReturnCode = -1, DebugMessage = "Invalid cache operation " + raiseEventRequest.Cache }, sendParameters); return; } customEvent.Cache = raiseEventRequest.Cache; } break; } case (byte) ReceiverGroup.MasterClient: { recipients = new[] {this.Actors[0]}; break; } default: { peer.SendOperationResponse( new OperationResponse { OperationCode = raiseEventRequest.OperationRequest.OperationCode, ReturnCode = -1, DebugMessage = "Invalid ReceiverGroup " + raiseEventRequest.ReceiverGroup }, sendParameters); return; } } this.PublishEvent(customEvent, recipients, sendParameters); }
/// <summary> /// Handles the <see cref = "RaiseEventRequest" />: Sends a <see cref = "CustomEvent" /> to actors in the room. /// </summary> /// <param name = "peer"> /// The peer. /// </param> /// <param name = "raiseEventRequest"> /// The operation /// </param> /// <param name = "sendParameters"> /// The send Parameters. /// </param> protected virtual void HandleRaiseEventOperation(LitePeer peer, RaiseEventRequest raiseEventRequest, SendParameters sendParameters) { // get the actor who send the operation request Actor actor = this.GetActorByPeer(peer); if (actor == null) { return; } sendParameters.Flush = raiseEventRequest.Flush; if (raiseEventRequest.Cache == (byte)CacheOperation.RemoveFromRoomCache) { this.eventCache.RemoveEvents(raiseEventRequest); var response = new OperationResponse(raiseEventRequest.OperationRequest.OperationCode) { ReturnCode = 0 }; peer.SendOperationResponse(response, sendParameters); return; } if (raiseEventRequest.Cache == (byte)CacheOperation.RemoveFromCacheForActorsLeft) { var currentActorNumbers = this.Actors.GetActorNumbers(); this.eventCache.RemoveEventsForActorsNotInList(currentActorNumbers); var response = new OperationResponse(raiseEventRequest.OperationRequest.OperationCode) { ReturnCode = 0 }; peer.SendOperationResponse(response, sendParameters); return; } // publish the custom event var customEvent = new CustomEvent(actor.ActorNr, raiseEventRequest.EvCode, raiseEventRequest.Data); bool updateEventCache = false; IEnumerable <Actor> recipients; if (raiseEventRequest.Actors != null && raiseEventRequest.Actors.Length > 0) { recipients = this.Actors.GetActorsByNumbers(raiseEventRequest.Actors); } else if (raiseEventRequest.Group != 0) { ActorGroup group; if (this.actorGroups.TryGetValue(raiseEventRequest.Group, out group)) { recipients = group.GetExcludedList(actor); } else { return; } } else { switch ((ReceiverGroup)raiseEventRequest.ReceiverGroup) { case ReceiverGroup.All: recipients = this.Actors; updateEventCache = true; break; case ReceiverGroup.Others: recipients = this.Actors.GetExcludedList(actor); updateEventCache = true; break; case ReceiverGroup.MasterClient: recipients = new[] { this.Actors[0] }; break; default: peer.SendOperationResponse( new OperationResponse { OperationCode = raiseEventRequest.OperationRequest.OperationCode, ReturnCode = -1, DebugMessage = "Invalid ReceiverGroup " + raiseEventRequest.ReceiverGroup }, sendParameters); return; } } if (updateEventCache && raiseEventRequest.Cache != (byte)CacheOperation.DoNotCache) { string msg; if (!this.UpdateEventCache(actor, raiseEventRequest, out msg)) { peer.SendOperationResponse( new OperationResponse { OperationCode = raiseEventRequest.OperationRequest.OperationCode, ReturnCode = -1, DebugMessage = msg }, sendParameters); return; } } this.PublishEvent(customEvent, recipients, sendParameters); }
/// <summary> /// Sends a <see cref = "LeaveEvent" /> to all <see cref = "Actor" />s. /// </summary> /// <param name = "peer"> /// The peer. /// </param> /// <param name = "leaveRequest"> /// The leave operation. /// </param> protected virtual void PublishLeaveEvent(LitePeer peer, LeaveRequest leaveRequest) { if (this.Actors.Count > 0) { Actor actor = this.GetActorByPeer(peer); if (actor != null) { IEnumerable<int> actorNumbers = this.Actors.GetActorNumbers(); var leaveEvent = new LeaveEvent(actor.ActorNr, actorNumbers.ToArray()); this.PublishEvent(leaveEvent, this.Actors, new SendParameters()); } } }
private void HandleUpdateFlightControls(LitePeer peer, OperationRequest operationRequest, SendParameters sendParameters) { var op = new UpdateControlsRequest(peer.Protocol, operationRequest); if (peer.ValidateOperation(op, sendParameters) == false) { return; } DebugLog(peer, operationRequest); op.OnStart(); peer.SendOperationResponse(new OperationResponse { OperationCode = op.OperationRequest.OperationCode }, sendParameters); op.OnComplete(); }
/// <summary> /// Sends all cached events to a peer. /// </summary> /// <param name = "litePeer"> /// The lite peer that receives the events. /// </param> protected void PublishEventCache(LitePeer litePeer) { var @event = new CustomEvent(0, 0, null); foreach (KeyValuePair<int, EventCache> entry in this.eventCacheOld) { int actor = entry.Key; EventCache cache = entry.Value; @event.ActorNr = actor; foreach (KeyValuePair<byte, Hashtable> eventEntry in cache) { @event.Code = @eventEntry.Key; @event.Data = @eventEntry.Value; var eventData = new EventData(@event.Code, @event); litePeer.SendEvent(eventData, new SendParameters()); } } foreach (CustomEvent customEvent in this.eventCache) { var eventData = new EventData(customEvent.Code, customEvent); litePeer.SendEvent(eventData, new SendParameters()); } }
/// <summary> /// Handles the <see cref = "RaiseEventRequest" />: Sends a <see cref = "CustomEvent" /> to actors in the room. /// </summary> /// <param name = "peer"> /// The peer. /// </param> /// <param name = "raiseEventRequest"> /// The operation /// </param> /// <param name = "sendParameters"> /// The send Parameters. /// </param> protected virtual void HandleRaiseEventOperation(LitePeer peer, RaiseEventRequest raiseEventRequest, SendParameters sendParameters) { // get the actor who send the operation request Actor actor = this.GetActorByPeer(peer); if (actor == null) { return; } sendParameters.Flush = raiseEventRequest.Flush; if (raiseEventRequest.Cache == (byte)CacheOperation.RemoveFromRoomCache) { this.eventCache.RemoveEvents(raiseEventRequest); var response = new OperationResponse(raiseEventRequest.OperationRequest.OperationCode) { ReturnCode = 0 }; peer.SendOperationResponse(response, sendParameters); return; } if (raiseEventRequest.Cache == (byte)CacheOperation.RemoveFromCacheForActorsLeft) { var currentActorNumbers = this.Actors.GetActorNumbers(); this.eventCache.RemoveEventsForActorsNotInList(currentActorNumbers); var response = new OperationResponse(raiseEventRequest.OperationRequest.OperationCode) { ReturnCode = 0 }; peer.SendOperationResponse(response, sendParameters); return; } // publish the custom event var customEvent = new CustomEvent(actor.ActorNr, raiseEventRequest.EvCode, raiseEventRequest.Data) { Cache = raiseEventRequest.Cache }; bool updateEventCache = false; IEnumerable<Actor> recipients; if (raiseEventRequest.Actors != null && raiseEventRequest.Actors.Length > 0) { recipients = this.Actors.GetActorsByNumbers(raiseEventRequest.Actors); } else { switch ((ReceiverGroup)raiseEventRequest.ReceiverGroup) { case ReceiverGroup.All: recipients = this.Actors; updateEventCache = true; break; case ReceiverGroup.Others: recipients = this.Actors.GetExcludedList(actor); updateEventCache = true; break; case ReceiverGroup.MasterClient: recipients = new[] { this.Actors[0] }; break; default: peer.SendOperationResponse( new OperationResponse { OperationCode = raiseEventRequest.OperationRequest.OperationCode, ReturnCode = -1, DebugMessage = "Invalid ReceiverGroup " + raiseEventRequest.ReceiverGroup }, sendParameters); return; } } if (updateEventCache && raiseEventRequest.Cache != (byte)CacheOperation.DoNotCache) { if (!this.UpdateEventCache(actor, raiseEventRequest)) { peer.SendOperationResponse( new OperationResponse { OperationCode = raiseEventRequest.OperationRequest.OperationCode, ReturnCode = -1, DebugMessage = "Invalid cache operation " + raiseEventRequest.Cache }, sendParameters); return; } } this.PublishEvent(customEvent, recipients, sendParameters); }
/// <summary> /// This method is invoked sequentially for each operation request /// enqueued in the <see cref = "ExecutionFiber" /> using the /// <see cref = "EnqueueOperation" /> method. /// </summary> /// <param name = "peer"> /// The peer. /// </param> /// <param name = "operation"> /// The operation request. /// </param> /// <param name = "sendParameters"> /// The send Parameters. /// </param> protected virtual void ExecuteOperation(LitePeer peer, OperationRequest operation, SendParameters sendParameters) { }
/// <summary> /// Gets the actor for a <see cref = "LitePeer" />. /// </summary> /// <param name = "peer"> /// The peer. /// </param> /// <returns> /// The actor for the peer or null if no actor for the peer exists (this should not happen). /// </returns> protected Actor GetActorByPeer(LitePeer peer) { Actor actor = this.Actors.GetActorByPeer(peer); if (actor == null) { if (Log.IsWarnEnabled) { Log.WarnFormat("Actor not found for peer: {0}", peer.ConnectionId); } } return actor; }
/// <summary> /// This override disables the event publishing. /// </summary> /// <param name="peer"> /// The peer. /// </param> /// <param name="leaveRequest"> /// The <see cref="LeaveRequest"/> sent by the peer or null if the peer have been disconnected without sending a leave request. /// </param> /// <returns> /// the actor number. /// </returns> protected override int RemovePeerFromGame(LitePeer peer, LeaveRequest leaveRequest) { Actor actor = this.Actors.GetActorByPeer(peer); if (this.Actors.Remove(actor) == false) { if (Log.IsWarnEnabled) { Log.WarnFormat("RemovePeerFromGame - Actor to remove not found for peer: {0}", peer.ConnectionId); } return 0; } return actor.ActorNr; }
/// <summary> /// Executes the base <see cref="LiteGame.HandleJoinOperation">HandleJoinOperation</see> and then sends an updated game list to all <see cref="Actor"/>s in the lobby. /// </summary> /// <param name="peer"> /// The peer. /// </param> /// <param name="joinRequest"> /// The join request. /// </param> /// <param name="sendParameters"> /// The send Parameters. /// </param> /// <returns> /// The new actor /// </returns> protected virtual Actor HandleJoinOperation(LitePeer peer, JoinRequest joinRequest, SendParameters sendParameters) { Actor actor = base.HandleJoinOperation(peer, joinRequest, sendParameters); if (actor != null) { this.PublishGameList(actor); } return actor; }
/// <summary> /// This override disables the event publishing. /// </summary> /// <param name="peer"> /// The peer. /// </param> /// <param name="joinRequest"> /// The join request. /// </param> protected override void PublishJoinEvent(LitePeer peer, Lite.Operations.JoinRequest joinRequest) { // lobbies don't publish a join event to the clients }
/// <summary> /// Removes a peer from the game. /// This method is called if a client sends a <see cref = "LeaveRequest" /> or disconnects. /// </summary> /// <param name = "peer"> /// The <see cref = "LitePeer" /> to remove. /// </param> /// <param name="leaveRequest"> /// The <see cref="LeaveRequest"/> sent by the peer or null if the peer have been disconnected without sending a leave request. /// </param> /// <returns> /// The actor number of the removed actor. /// If the specified peer does not exists -1 will be returned. /// </returns> protected virtual int RemovePeerFromGame(LitePeer peer, LeaveRequest leaveRequest) { Actor actor = this.Actors.RemoveActorByPeer(peer); if (actor == null) { if (Log.IsWarnEnabled) { Log.WarnFormat("RemovePeerFromGame - Actor to remove not found for peer: {0}", peer.ConnectionId); } return -1; } this.eventCacheOld.Remove(actor.ActorNr); if (this.DeleteCacheOnLeave) { this.eventCache.RemoveEventsByActor(actor.ActorNr); } // raise leave event this.PublishLeaveEvent(actor, leaveRequest); return actor.ActorNr; }
/// <summary> /// Handles the <see cref = "RaiseEventRequest" />: Sends a <see cref = "CustomEvent" /> to actors in the room. /// </summary> /// <param name = "peer"> /// The peer. /// </param> /// <param name = "raiseEventRequest"> /// The operation /// </param> /// <param name = "sendParameters"> /// The send Parameters. /// </param> protected virtual void HandleRaiseEventOperation(LitePeer peer, RaiseEventRequest raiseEventRequest, SendParameters sendParameters) { // get the actor who send the operation request Actor actor = this.GetActorByPeer(peer); if (actor == null) { return; } var customEvent = new CustomEvent(actor.ActorNr, raiseEventRequest.EvCode, raiseEventRequest.Data); if (raiseEventRequest.Cache == (byte)CacheOperation.RemoveFromRoomCache) { this.roomEventCache.RemoveEvents(raiseEventRequest); var response = new OperationResponse(raiseEventRequest.OperationRequest.OperationCode) { ReturnCode = 0 }; peer.SendOperationResponse(response, sendParameters); return; } // publish the custom event IEnumerable <Actor> recipients; if (raiseEventRequest.Actors != null && raiseEventRequest.Actors.Length > 0) { recipients = this.Actors.GetActorsByNumbers(raiseEventRequest.Actors); sendParameters.Flush = raiseEventRequest.Flush; this.PublishEvent(customEvent, recipients, sendParameters); return; } switch (raiseEventRequest.ReceiverGroup) { case (byte)ReceiverGroup.All: { recipients = this.Actors; if (raiseEventRequest.Cache == (byte)CacheOperation.AddToRoomCache) { customEvent.Cache = raiseEventRequest.Cache; this.roomEventCache.AddEvent(customEvent); } else if (raiseEventRequest.Cache == (byte)CacheOperation.AddToRoomCacheGlobal) { customEvent.ActorNr = 0; customEvent.Cache = raiseEventRequest.Cache; this.roomEventCache.AddEvent(customEvent); } else if (raiseEventRequest.Cache != (byte)CacheOperation.DoNotCache) { if (!this.UpdateEventCache(actor, raiseEventRequest, raiseEventRequest.EvCode)) { peer.SendOperationResponse( new OperationResponse { OperationCode = raiseEventRequest.OperationRequest.OperationCode, ReturnCode = -1, DebugMessage = "Invalid cache operation " + raiseEventRequest.Cache }, sendParameters); return; } customEvent.Cache = raiseEventRequest.Cache; } break; } case (byte)ReceiverGroup.Others: { recipients = this.Actors.GetExcludedList(actor); if (raiseEventRequest.Cache == (byte)CacheOperation.AddToRoomCache) { customEvent.Cache = raiseEventRequest.Cache; this.roomEventCache.AddEvent(customEvent); } else if (raiseEventRequest.Cache == (byte)CacheOperation.AddToRoomCacheGlobal) { customEvent.ActorNr = 0; customEvent.Cache = raiseEventRequest.Cache; this.roomEventCache.AddEvent(customEvent); } else if (raiseEventRequest.Cache != (byte)CacheOperation.DoNotCache) { if (!this.UpdateEventCache(actor, raiseEventRequest, raiseEventRequest.EvCode)) { peer.SendOperationResponse( new OperationResponse { OperationCode = raiseEventRequest.OperationRequest.OperationCode, ReturnCode = -1, DebugMessage = "Invalid cache operation " + raiseEventRequest.Cache }, sendParameters); return; } customEvent.Cache = raiseEventRequest.Cache; } break; } case (byte)ReceiverGroup.MasterClient: { recipients = new[] { this.Actors[0] }; break; } default: { peer.SendOperationResponse( new OperationResponse { OperationCode = raiseEventRequest.OperationRequest.OperationCode, ReturnCode = -1, DebugMessage = "Invalid ReceiverGroup " + raiseEventRequest.ReceiverGroup }, sendParameters); return; } } this.PublishEvent(customEvent, recipients, sendParameters); }
private void HandleLiteOperations(LitePeer peer, OperationRequest operationRequest, SendParameters sendParameters) { string message = string.Format("Unknown operation code {0}", (Lite.Operations.OperationCode)operationRequest.OperationCode); peer.SendOperationResponse( new OperationResponse { OperationCode = operationRequest.OperationCode, ReturnCode = -1, DebugMessage = message }, sendParameters); if (Log.IsWarnEnabled) { Log.Warn(message); } }
/// <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; }
protected bool ValidateGame(LitePeer peer, OperationRequest operationRequest, SendParameters sendParameters) { var gamePeer = (GameClientPeer)peer; // check if the game is open if (this.isOpen == false) { var errorResponse = new OperationResponse { OperationCode = operationRequest.OperationCode, ReturnCode = (int)ErrorCode.GameClosed, DebugMessage = "Game closed" }; peer.SendOperationResponse(errorResponse, sendParameters); gamePeer.OnJoinFailed(ErrorCode.GameClosed); return false; } // check if the maximum number of players has already been reached if (this.maxPlayers > 0 && this.Actors.Count >= this.maxPlayers) { var errorResponse = new OperationResponse { OperationCode = operationRequest.OperationCode, ReturnCode = (int)ErrorCode.GameFull, DebugMessage = "Game full" }; peer.SendOperationResponse(errorResponse, sendParameters); gamePeer.OnJoinFailed(ErrorCode.GameFull); return false; } return true; }
/// <summary> /// Enqueues an <see cref = "OperationRequest" /> to the end of the execution queue. /// </summary> /// <param name = "peer"> /// The peer. /// </param> /// <param name = "operationRequest"> /// The operation request to enqueue. /// </param> /// <param name = "sendParameters"> /// The send Parameters. /// </param> /// <remarks> /// <see cref = "ExecuteOperation" /> is called sequentially for each operation request /// stored in the execution queue. /// Using an execution queue ensures that operation request are processed in order /// and sequentially to prevent object synchronization (multi threading). /// </remarks> public void EnqueueOperation(LitePeer peer, OperationRequest operationRequest, SendParameters sendParameters) { this.ExecutionFiber.Enqueue(() => this.ExecuteOperation(peer, operationRequest, 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> /// 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; }
/// <summary> /// Handles the <see cref = "GetPropertiesRequest" /> operation: Sends the properties with the <see cref = "OperationResponse" />. /// </summary> /// <param name = "peer"> /// The peer. /// </param> /// <param name = "getPropertiesRequest"> /// The operation to handle. /// </param> /// <param name = "sendParameters"> /// The send Parameters. /// </param> protected virtual void HandleGetPropertiesOperation(LitePeer peer, GetPropertiesRequest getPropertiesRequest, SendParameters sendParameters) { var response = new GetPropertiesResponse(); // check if game properties should be returned if ((getPropertiesRequest.PropertyType & (byte)PropertyType.Game) == (byte)PropertyType.Game) { response.GameProperties = this.Properties.GetProperties(getPropertiesRequest.GamePropertyKeys); } // check if actor properties should be returned if ((getPropertiesRequest.PropertyType & (byte)PropertyType.Actor) == (byte)PropertyType.Actor) { response.ActorProperties = new Hashtable(); if (getPropertiesRequest.ActorNumbers == null) { foreach (Actor actor in this.Actors) { Hashtable actorProperties = actor.Properties.GetProperties(getPropertiesRequest.ActorPropertyKeys); response.ActorProperties.Add(actor.ActorNr, actorProperties); } } else { foreach (int actorNumber in getPropertiesRequest.ActorNumbers) { Actor actor = this.Actors.GetActorByNumber(actorNumber); if (actor != null) { Hashtable actorProperties = actor.Properties.GetProperties(getPropertiesRequest.ActorPropertyKeys); response.ActorProperties.Add(actorNumber, actorProperties); } } } } peer.SendOperationResponse(new OperationResponse(getPropertiesRequest.OperationRequest.OperationCode, response), sendParameters); }
/// <summary> /// Updates the lobby when an <see cref = "Actor" /> leaves (disconnect, <see cref = "LeaveRequest" />, <see cref = "JoinRequest" /> for another game). /// </summary> /// <param name = "peer"> /// The <see cref = "LitePeer" /> to remove. /// </param> /// <param name="leaveRequest"> /// The <see cref="LeaveRequest"/> sent by the peer or null if the peer have been disconnected without sending a leave request. /// </param> /// <returns> /// The actore number of the removed actor. /// If the specified peer does not exists -1 will be returned. /// </returns> protected override int RemovePeerFromGame(LitePeer peer, LeaveRequest leaveRequest) { int actorNr = base.RemovePeerFromGame(peer, leaveRequest); this.UpdateLobby(); return actorNr; }
/// <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; } if (this.LogQueue.Log.IsDebugEnabled) { 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; } if (this.LogQueue.Log.IsDebugEnabled) { 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; } case OperationCode.ChangeGroups: { var changeGroupsOperation = new ChangeGroups(peer.Protocol, operationRequest); if (peer.ValidateOperation(changeGroupsOperation, sendParameters) == false) { return; } changeGroupsOperation.OnStart(); this.HandleChangeGroupsOperation(peer, changeGroupsOperation, sendParameters); changeGroupsOperation.OnComplete(); 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 = "SetPropertiesRequest" /> and sends event <see cref = "PropertiesChangedEvent" /> to all <see cref = "Actor" />s in the room. /// </summary> /// <param name = "peer"> /// The peer. /// </param> /// <param name = "setPropertiesRequest"> /// The <see cref = "SetPropertiesRequest" /> operation to handle. /// </param> /// <param name = "sendParameters"> /// The send Parameters. /// </param> protected virtual void HandleSetPropertiesOperation(LitePeer peer, SetPropertiesRequest setPropertiesRequest, SendParameters sendParameters) { if (setPropertiesRequest.ActorNumber > 0) { Actor actor = this.Actors.GetActorByNumber(setPropertiesRequest.ActorNumber); if (actor == null) { peer.SendOperationResponse( new OperationResponse { OperationCode = setPropertiesRequest.OperationRequest.OperationCode, ReturnCode = -1, DebugMessage = string.Format("Actor with number {0} not found.", setPropertiesRequest.ActorNumber) }, sendParameters); return; } actor.Properties.SetProperties(setPropertiesRequest.Properties); } else { this.Properties.SetProperties(setPropertiesRequest.Properties); } peer.SendOperationResponse(new OperationResponse { OperationCode = setPropertiesRequest.OperationRequest.OperationCode }, sendParameters); // if the optional paramter Broadcast is set a EvPropertiesChanged // event will be send to room actors if (setPropertiesRequest.Broadcast) { Actor actor = this.Actors.GetActorByPeer(peer); IEnumerable<Actor> recipients = this.Actors.GetExcludedList(actor); var propertiesChangedEvent = new PropertiesChangedEvent(actor.ActorNr) { TargetActorNumber = setPropertiesRequest.ActorNumber, Properties = setPropertiesRequest.Properties }; this.PublishEvent(propertiesChangedEvent, recipients, sendParameters); } }
/// <summary> /// Removes a peer from the game. /// This method is called if a client sends a <see cref = "LeaveRequest" /> or disconnects. /// </summary> /// <param name = "peer"> /// The <see cref = "LitePeer" /> to remove. /// </param> /// <returns> /// The actor number of the removed actor. /// If the specified peer does not exists -1 will be returned. /// </returns> protected virtual int RemovePeerFromGame(LitePeer peer) { Actor actor = this.Actors.RemoveActorByPeer(peer); if (actor == null) { if (Log.IsWarnEnabled) { Log.WarnFormat("RemovePeerFromGame - Actor to remove not found for peer: {0}", peer.ConnectionId); } return -1; } this.cachedEvents.Remove(actor.ActorNr); // raise leave event if (this.Actors.Count > 0) { IEnumerable<int> actorNumbers = this.Actors.GetActorNumbers(); var leaveEvent = new LeaveEvent(actor.ActorNr, actorNumbers.ToArray()); this.PublishEvent(leaveEvent, this.Actors, new SendParameters()); } return actor.ActorNr; }
/// <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, joinRequest.ActorNr, out actor) == false) { peer.SendOperationResponse( new OperationResponse { OperationCode = joinRequest.OperationRequest.OperationCode, ReturnCode = -1, DebugMessage = "Peer already joined the specified game." }, sendParameters); return(null); } // check if a room removal is in progress and cancel it if so if (this.RemoveTimer != null) { this.RemoveTimer.Dispose(); this.RemoveTimer = null; } // set game properties for join from the first actor (game creator) if (this.Actors.Count == 1) { this.DeleteCacheOnLeave = joinRequest.DeleteCacheOnLeave; this.SuppressRoomEvents = joinRequest.SuppressRoomEvents; 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> /// Tries to add a <see cref = "LitePeer" /> to this game instance. /// </summary> /// <param name = "peer"> /// The peer to add. /// </param> /// <param name = "actor"> /// When this method returns this out param contains the <see cref = "Actor" /> associated with the <paramref name = "peer" />. /// </param> /// <returns> /// Returns true if no actor exists for the specified peer and a new actor for the peer has been successfully added. /// The actor parameter is set to the newly created <see cref = "Actor" /> instance. /// Returns false if an actor for the specified peer already exists. /// The actor paramter is set to the existing <see cref = "Actor" /> for the specified peer. /// </returns> protected virtual bool TryAddPeerToGame(LitePeer peer, out Actor actor) { // check if the peer already exists in this game actor = this.Actors.GetActorByPeer(peer); if (actor != null) { return false; } // create new actor instance actor = new Actor(peer); this.actorNumberCounter++; actor.ActorNr = this.actorNumberCounter; this.Actors.Add(actor); if (Log.IsDebugEnabled) { Log.DebugFormat("Actor added: {0} to game: {1}", actor.ActorNr, this.Name); } return true; }
/// <summary> /// Gets an actor by a specified peer. /// </summary> /// <param name="peer"> /// The peer. /// </param> /// <returns> /// Returns the actor for the specified peer or null /// if no actor for the specified peer was found. /// </returns> public Actor GetActorByPeer(LitePeer peer) { return(this.FirstOrDefault(actor => actor.Peer == peer)); }