/// <summary> /// Distribute Events to Registered objects /// </summary> /// <param name="notifiers">Enumerable of Registered Object</param> /// <param name="player">player who made the check</param> /// <param name="data">Check data for Args</param> private static void NotifyObjects(IList<IDOLEventHandler> notifiers, GamePlayer player, LosCheckData data) { // Lock notifiers list. lock(((ICollection)notifiers).SyncRoot) { foreach(IDOLEventHandler notifier in notifiers) { notifier.Notify(GameObjectEvent.FinishedLosCheck, player, data); } // Clear at end, so a new list can be made for next call notifiers.Clear(); } }
/// <summary> /// LoS Responses are handled through this method /// </summary> /// <param name="player">Player replying</param> /// <param name="response">Client response</param> /// <param name="targetOID">Target OID to which the Check was made</param> private void LosResponseHandler(GamePlayer player, ushort response, ushort sourceOID, ushort targetOID) { if(player == null || sourceOID == 0 || targetOID == 0) return; // get time long sent = GameTimer.GetTickCount(); long time = sent; // Check result bool losOK = (response & 0x100) == 0x100; // key for pending Tuple<GamePlayer, ushort, ushort> checkerKey = new Tuple<GamePlayer, ushort, ushort>(player, sourceOID, targetOID); // Object from OID GameObject source = player.CurrentRegion.GetObject(sourceOID); GameObject target = player.CurrentRegion.GetObject(targetOID); // FIXME remove debug if(LOSMGR_DEBUG_LEVEL >= LOSMGR_DEBUG_WARN) log.Warn("LOSMGR_W : Los Check Finished - Player : "+player.Name+" Source : "+(source != null ? source.Name : "null")+"("+sourceOID+") Target : "+(target != null ? target.Name : "null")+"("+targetOID+") LoS : " + (losOK ? "OK" : "KO")); // we have a response, it should be in pending lock(((ICollection)PendingChecks).SyncRoot) { // We have some data into pending cache if(PendingChecks.ContainsKey(checkerKey)) { //We should remove it sent = PendingChecks[checkerKey]; PendingChecks.Remove(checkerKey); // Update Client Stats if(ClientStats.ContainsKey(player)) { long total = ClientStats[player].Item1 * ClientStats[player].Item2; total += (time - sent); int count = ClientStats[player].Item1+1; ClientStats[player] = new Tuple<int, int, int>(count, (int)total/count, (int)(time - sent)); // FIXME debug if(LOSMGR_DEBUG_LEVEL >= LOSMGR_DEBUG_DEBUG) log.Warn("LOSMGR_D : Clients Stats Update : "+player.Name+", count : "+count+", average : "+((int)total/count)+", instant : "+((int)(time - sent))); } else { ClientStats[player] = new Tuple<int, int, int>(1, (int)(time - sent), (int)(time - sent)); } } else { //No Pending Object, it's a wild one ! // FIXME Display debug if(LOSMGR_DEBUG_LEVEL >= LOSMGR_DEBUG_INFO) log.Warn("LOSMGR_I : Los Check Without pending objects - Player : "+player.Name+" Source : "+(source != null ? source.Name : "null")+"("+sourceOID+") Target : "+(target != null ? target.Name : "null")+"("+targetOID+") LoS : " + (losOK ? "OK" : "KO") + " !"); } } // Update all caches if(source != null && target != null) { int timeout = GetDefaultTimeouts(source, target); lock(((ICollection)ResponsesCache).SyncRoot) { UpdateVincinityLosCache(source, target, losOK, time); UpdateVincinityLosCache(target, source, losOK, time); UpdateLosCacheItem(source, target, losOK, timeout, time); } } // key for registered Tuple<GameObject, GameObject> cachekey = new Tuple<GameObject, GameObject>(source, target); Tuple<GameObject, GameObject> rcachekey = new Tuple<GameObject, GameObject>(target, source); // We should Notify objects asking for this Check or the reverse one. lock(((ICollection)RegisteredLosEvents).SyncRoot) { LosCheckData losData = new LosCheckData(source, target, sent, losOK); if(RegisteredLosEvents.ContainsKey(cachekey)) { NotifyObjects(RegisteredLosEvents[cachekey], player, losData); } if(RegisteredLosEvents.ContainsKey(rcachekey)) { NotifyObjects(RegisteredLosEvents[rcachekey], player, losData); } } }