/// <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> /// Helper method of <see cref = "HandleRaiseEventOperation" />. /// Stores an event for new actors. /// </summary> /// <param name = "actor"> /// The actor. /// </param> /// <param name = "raiseEventRequest"> /// The raise event request. /// </param> /// <returns> /// True if <see cref = "RaiseEventRequest.Cache" /> is valid. /// </returns> protected bool UpdateEventCache(Actor actor, RaiseEventRequest raiseEventRequest) { CustomEvent customEvent; switch (raiseEventRequest.Cache) { case (byte)CacheOperation.AddToRoomCache: customEvent = new CustomEvent(actor.ActorNr, raiseEventRequest.EvCode, raiseEventRequest.Data) { Cache = raiseEventRequest.Cache }; this.eventCache.AddEvent(customEvent); return true; case (byte)CacheOperation.AddToRoomCacheGlobal: customEvent = new CustomEvent(0, raiseEventRequest.EvCode, raiseEventRequest.Data) { Cache = raiseEventRequest.Cache }; this.eventCache.AddEvent(customEvent); return true; case (byte)CacheOperation.MergeCache: { EventCache eventCache; if (!this.eventCacheOld.TryGetValue(actor.ActorNr, out eventCache)) { eventCache = new EventCache(); this.eventCacheOld.Add(actor.ActorNr, eventCache); } Hashtable @event; if (eventCache.TryGetValue(raiseEventRequest.EvCode, out @event)) { // null events are removed if (raiseEventRequest.Data == null) { eventCache.Remove(raiseEventRequest.EvCode); } else { // merge or delete foreach (DictionaryEntry pair in raiseEventRequest.Data) { // null values are removed if (pair.Value == null) { @event.Remove(pair.Key); } else { @event[pair.Key] = pair.Value; } } } } else if (raiseEventRequest.Data != null) { // new @event = raiseEventRequest.Data; eventCache.Add(raiseEventRequest.EvCode, @event); } return true; } case (byte)CacheOperation.RemoveCache: { EventCache eventCache; if (!this.eventCacheOld.TryGetValue(actor.ActorNr, out eventCache)) { return true; } eventCache.Remove(raiseEventRequest.EvCode); return true; } case (byte)CacheOperation.ReplaceCache: { EventCache eventCache; if (!this.eventCacheOld.TryGetValue(actor.ActorNr, out eventCache)) { eventCache = new EventCache(); this.eventCacheOld.Add(actor.ActorNr, eventCache); } eventCache.Remove(raiseEventRequest.EvCode); if (raiseEventRequest.Data != null) { Hashtable @event = raiseEventRequest.Data; eventCache.Add(raiseEventRequest.EvCode, @event); } return true; } default: { return false; } } }
/// <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> /// Sends the complete list of games to one actor in the lobby. /// </summary> /// <param name="actor"> /// The actor. /// </param> private void PublishGameList(Actor actor) { // Room list needs to be cloned because it is serialized in other thread and is changed at the same time var customEvent = new CustomEvent(actor.ActorNr, (byte)LiteLobbyEventCode.GameList, (Hashtable)this.roomList.Clone()); this.PublishEvent(customEvent, actor, new SendParameters { Unreliable = true }); }
/// <summary> /// Sends the change list to all users in the lobby and then clears it. /// </summary> private void PublishChangeList() { if (this.changedRoomList.Count > 0 && this.Actors.Count > 0) { var customEvent = new CustomEvent(0, (byte)LiteLobbyEventCode.GameListUpdate, this.changedRoomList); // PublishEvent(hashtable) uses a reference to hashtable, which means you can not clear it (see below) this.PublishEvent(customEvent, this.Actors, new SendParameters { Unreliable = true }); } this.changedRoomList = new Hashtable(); // creating a new hashtable, as PublishEvent() uses just a ref to the data to be sent this.SchedulePublishChanges(); }
/// <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> /// Helper method of <see cref = "HandleRaiseEventOperation" />. /// Stores an event for new actors. /// </summary> /// <param name = "actor"> /// The actor. /// </param> /// <param name = "raiseEventRequest"> /// The raise event request. /// </param> /// <param name="msg"> /// Contains an error message if the method returns false. /// </param> /// <returns> /// True if <see cref = "RaiseEventRequest.Cache" /> is valid. /// </returns> protected bool UpdateEventCache(Actor actor, RaiseEventRequest raiseEventRequest, out string msg) { msg = null; CustomEvent customEvent; switch (raiseEventRequest.Cache) { case (byte)CacheOperation.DoNotCache: return true; case (byte)CacheOperation.AddToRoomCache: customEvent = new CustomEvent(actor.ActorNr, raiseEventRequest.EvCode, raiseEventRequest.Data); this.eventCache.AddEvent(customEvent); return true; case (byte)CacheOperation.AddToRoomCacheGlobal: customEvent = new CustomEvent(0, raiseEventRequest.EvCode, raiseEventRequest.Data); this.eventCache.AddEvent(customEvent); return true; } // cache operations for the actor event cache currently only working with hashtable data Hashtable eventData; if (raiseEventRequest.Data == null || raiseEventRequest.Data is Hashtable) { eventData = (Hashtable)raiseEventRequest.Data; } else { msg = string.Format("Cache operation '{0}' requires a Hashtable as event data.", raiseEventRequest.Cache); return false; } switch (raiseEventRequest.Cache) { case (byte)CacheOperation.MergeCache: this.actorEventCache.MergeEvent(actor.ActorNr, raiseEventRequest.EvCode, eventData); return true; case (byte)CacheOperation.RemoveCache: this.actorEventCache.RemoveEvent(actor.ActorNr, raiseEventRequest.EvCode); return true; case (byte)CacheOperation.ReplaceCache: this.actorEventCache.ReplaceEvent(actor.ActorNr, raiseEventRequest.EvCode, eventData); return true; default: msg = string.Format("Unknown cache operation '{0}'.", raiseEventRequest.Cache); return false; } }