public void From_should_return_correct_subset_from_array() { var items = new List <string>() { "meat", "cheese", "beer", "bread" }; var from = items.From("beer"); Assert.True(from.SequenceEqual(new[] { "beer", "bread" })); }
public void From_should_return_entire_array_if_item_is_at_front_of_array() { var items = new List <string>() { "meat", "cheese", "beer", "bread" }; var from = items.From("meat"); Assert.True(from.SequenceEqual(items)); }
public void From_should_return_empty_set_when_item_not_found() { var items = new List <int>() { 1, 2, 3, 4, 5, 6 }; var from7 = items.From(7).Take(2); from7.Count().ShouldBe(0); }
static SoloLevelingUtility() { Ditto.Connected += async() => { // Recheck the valid links _links.Clear(); await Ditto.Database.ReadAsync(uow => { _links.AddRange(uow.Links.GetAllWithLinks(l => l.Type == LinkType.SoloLeveling)); }).ConfigureAwait(false); // TODO: Recalculate number of messages foreach (var link in _links) { var messages = new List <IMessage>(); var lastRecordedDate = GetLastRecordedDateFromLink(link); ulong lastMessageId = ulong.MaxValue; while (true) { var messagesChunk = Enumerable.Empty <IMessage>(); if (lastMessageId != ulong.MaxValue) { messagesChunk = (await link.Channel.GetMessagesAsync(lastMessageId, Direction.Before, 100, CacheMode.AllowDownload).ToListAsync().ConfigureAwait(false)) .SelectMany(m => m) .Where(m => m.CreatedAt.UtcDateTime > link.Date); } else { messagesChunk = (await link.Channel.GetMessagesAsync(100, CacheMode.AllowDownload).ToListAsync().ConfigureAwait(false)) .SelectMany(m => m) .Where(m => m.CreatedAt.UtcDateTime > link.Date); } messages.AddRange(messagesChunk); lastMessageId = messagesChunk.LastOrDefault()?.Id ?? ulong.MaxValue; // Cancel when the last recorded message is larger than the earliest message date of the collection, meaning we're good to go. if (lastRecordedDate > messages.Min(x => x.CreatedAt.UtcDateTime)) { messages = messages.From(x => x.CreatedAt.UtcDateTime > lastRecordedDate).ToList(); break; } // Cancel when message count is less than the maximum. if (messagesChunk.Count() < 100) { break; } } // Process any missed messages if (messages.Count > 0) { foreach (var message in messages) { await ProcessMessageAsync(message).ConfigureAwait(false); } } } // Start listening to new messages await Ditto.Client.DoAsync(client => { client.MessageReceived += OnMessageReceived; }).ConfigureAwait(false); }; Ditto.Exit += async() => { await Ditto.Client.DoAsync(client => { client.MessageReceived -= OnMessageReceived; }).ConfigureAwait(false); }; }
/// <summary> /// Run tasks of all phases including and after the given phase. /// </summary> /// <param name="fromPhase">Optional. The phase to start the run from.</param> /// <returns>A task that is completed when all such tasks have been completed, or /// there is failure when <see cref="Phase.Recover"/> is disabled.</returns> /// <remarks> /// It is safe to call this method multiple times. It will only run once. /// </remarks> public Task <Done> Run(string fromPhase = null) { if (_runStarted.CompareAndSet(false, true)) { var debugEnabled = Log.IsDebugEnabled; Func <List <string>, Task <Done> > loop = null; loop = remainingPhases => { var phase = remainingPhases.FirstOrDefault(); if (phase == null) { return(TaskEx.Completed); } var remaining = remainingPhases.Skip(1).ToList(); Task <Done> phaseResult = null; ImmutableList <Tuple <string, Func <Task <Done> > > > phaseTasks; if (!_tasks.TryGetValue(phase, out phaseTasks)) { if (debugEnabled) { Log.Debug("Performing phase [{0}] with [0] tasks.", phase); } phaseResult = TaskEx.Completed; } else { if (debugEnabled) { Log.Debug("Performing phase [{0}] with [{1}] tasks: [{2}]", phase, phaseTasks.Count, string.Join(",", phaseTasks.Select(x => x.Item1))); } // note that tasks within same phase are performed in parallel var recoverEnabled = Phases[phase].Recover; var result = Task.WhenAll <Done>(phaseTasks.Select(x => { var taskName = x.Item1; var task = x.Item2; try { // need to begin execution of task var r = task(); if (recoverEnabled) { return(r.ContinueWith(tr => { if (tr.IsCanceled || tr.IsFaulted) { Log.Warning("Task [{0}] failed in phase [{1}]: {2}", taskName, phase, tr.Exception?.Flatten().Message); } return Done.Instance; })); } return(r); } catch (Exception ex) { // in case task.Start() throws if (recoverEnabled) { Log.Warning("Task [{0}] failed in phase [{1}]: {2}", taskName, phase, ex.Message); return(TaskEx.Completed); } return(TaskEx.FromException <Done>(ex)); } })).ContinueWith(tr => { // forces downstream error propagation if recover is disabled var force = tr.Result; return(Done.Instance); }); var timeout = Phases[phase].Timeout; var deadLine = MonotonicClock.Elapsed + timeout; Task <Done> timeoutFunction = null; try { timeoutFunction = After(timeout, System.Scheduler, () => { if (phase == CoordinatedShutdown.PhaseActorSystemTerminate && MonotonicClock.ElapsedHighRes < deadLine) { // too early, i.e. triggered by system termination return(result); } else if (result.IsCompleted) { return(TaskEx.Completed); } else if (recoverEnabled) { Log.Warning("Coordinated shutdown phase [{0}] timed out after {1}", phase, timeout); return(TaskEx.Completed); } else { return (TaskEx.FromException <Done>( new TimeoutException( $"Coordinated shutdown phase[{phase}] timed out after {timeout}"))); } }); } catch (SchedulerException) { // The call to `after` threw SchedulerException, triggered by system termination timeoutFunction = result; } catch (InvalidOperationException) { // The call to `after` threw SchedulerException, triggered by Scheduler being in unset state timeoutFunction = result; } phaseResult = Task.WhenAny <Done>(result, timeoutFunction).Unwrap(); } if (!remaining.Any()) { return(phaseResult); } return(phaseResult.ContinueWith(tr => { // force any exceptions to be rethrown so next phase stops // and so failure gets propagated back to caller var r = tr.Result; return loop(remaining); }).Unwrap()); }; var runningPhases = (fromPhase == null ? OrderedPhases // all : OrderedPhases.From(fromPhase)).ToList(); var done = loop(runningPhases); done.ContinueWith(tr => { if (!tr.IsFaulted && !tr.IsCanceled) { _runPromise.SetResult(tr.Result); } else { // ReSharper disable once PossibleNullReferenceException _runPromise.SetException(tr.Exception.Flatten()); } }); } return(_runPromise.Task); }
public void From_should_return_entire_array_if_item_is_at_front_of_array() { var items = new List<string>() { "meat", "cheese", "beer", "bread" }; var from = items.From("meat"); Assert.True(from.SequenceEqual(items)); }
public void From_should_return_correct_subset_from_array() { var items = new List<string>() {"meat", "cheese", "beer", "bread"}; var from = items.From("beer"); Assert.True(from.SequenceEqual(new[]{ "beer", "bread" })); }
public void From_should_return_empty_set_when_item_not_found() { var items = new List<int>() {1, 2, 3, 4, 5, 6}; var from7 = items.From(7).Take(2); from7.Count().ShouldBe(0); }
public void FireArrow(List<Tile> line,bool free_attack) { if(!free_attack && StunnedThisTurn()){ return; } int mod = -30; //bows have base accuracy 45% /*if(magic_trinkets.Contains(MagicTrinketType.RING_OF_KEEN_SIGHT)){ mod = -15; //keen sight now only affects trap detection }*/ if(this == player && Bow.status[EquipmentStatus.ONE_ARROW_LEFT]){ mod = 25; //...but the last arrow gets a bonus } mod += TotalSkill(SkillType.COMBAT); Tile t = null; Actor a = null; bool solid_object_hit = false; bool no_terrain_collision_message = free_attack; //don't show "the arrow hits the wall" for echoes. List<string> misses = new List<string>(); List<Actor> missed = new List<Actor>(); List<Tile> animation_line = new List<Tile>(line); line.RemoveAt(0); //remove the source of the arrow first if(line.Count > 12){ line = line.GetRange(0,Math.Min(12,line.Count)); } int flaming_arrow_start = HasAttr(AttrType.FIERY_ARROWS)? 0 : -1; //tracks where an arrow caught fire bool blocked_by_armor_miss = false; bool blocked_by_root_shell_miss = false; for(int i=0;i<line.Count;++i){ a = line[i].actor(); t = line[i]; if(a != null){ no_terrain_collision_message = true; int plus_to_hit = mod - a.TotalSkill(SkillType.DEFENSE)*3; bool hit = true; if(!a.IsHit(plus_to_hit)){ hit = false; int armor_value = a.TotalProtectionFromArmor(); if(a != player){ armor_value = a.TotalSkill(SkillType.DEFENSE); //if monsters have Defense skill, it's from armor } int roll = R.Roll(55 - plus_to_hit); if(roll <= armor_value * 3){ blocked_by_armor_miss = true; } else{ if(a.HasAttr(AttrType.ROOTS) && roll <= (armor_value + 10) * 3){ //potion of roots gives 10 defense blocked_by_root_shell_miss = true; } } } else{ if(a.HasAttr(AttrType.TUMBLING)){ a.attrs[AttrType.TUMBLING] = 0; hit = false; } } if(R.CoinFlip() && !CanSee(a)){ //extra 50% miss chance for enemies you can't see hit = false; blocked_by_armor_miss = false; blocked_by_root_shell_miss = false; } if(hit || blocked_by_armor_miss || blocked_by_root_shell_miss){ solid_object_hit = true; break; } else{ misses.Add("The arrow misses " + a.the_name + ". "); missed.Add(a); } a = null; } if(!t.passable){ a = null; solid_object_hit = true; break; } if(flaming_arrow_start == -1 && t.IsBurning()){ flaming_arrow_start = i; } } if(!free_attack){ if(Bow != null && Bow.status[EquipmentStatus.ONE_ARROW_LEFT]){ B.Add(You("take") + " careful aim. ",this); B.Add(You("fire") + " " + Your() + " last arrow. ",this); } else{ if(HasAttr(AttrType.FIERY_ARROWS)){ B.Add(You("fire") + " a flaming arrow. ",this); } else{ B.Add(You("fire") + " an arrow. ",this); } } B.DisplayNow(); } int idx = 0; /*foreach(Tile tile2 in animation_line){ if(tile2.seen){ ++idx; //todo: remove idx here, right? } else{ animation_line = animation_line.To(tile2); if(animation_line.Count > 0){ animation_line.RemoveAt(animation_line.Count - 1); } break; } }*/ if(animation_line.Count > 0){ Screen.CursorVisible = false; PhysicalObject o = t; if(a != null){ o = a; } animation_line = animation_line.To(o); if(flaming_arrow_start >= 0 && !M.wiz_dark && !player.HasAttr(AttrType.BLIND)){ //fire should be visible unless darkened or blind List<Tile> first_line = animation_line.ToCount(flaming_arrow_start+2); List<Tile> second_line = animation_line.FromCount(flaming_arrow_start+2); if(first_line.Count > 0){ Screen.AnimateBoltProjectile(animation_line.ToCount(flaming_arrow_start+2),Color.DarkYellow,20); } Screen.CursorVisible = false; if(second_line.Count > 0){ Screen.AnimateBoltProjectile(animation_line.FromCount(flaming_arrow_start+2),Color.RandomFire,20); } } else{ Screen.AnimateBoltProjectile(animation_line,Color.DarkYellow,20); } Screen.CursorVisible = false; if(this == player && solid_object_hit && !player.CanSee(o) && (o is Actor || !o.tile().seen)){ Screen.AnimateMapCell(o.row,o.col,new colorchar('?',Color.DarkGray),50); } Screen.CursorVisible = false; } idx = 0; foreach(string s in misses){ B.Add(s,missed[idx]); if(missed[idx] != player){ missed[idx].player_visibility_duration = -1; if(HasLOE(missed[idx])){ missed[idx].target = this; missed[idx].target_location = tile(); } } ++idx; } if(flaming_arrow_start != -1){ foreach(Tile affected in line.FromCount(flaming_arrow_start+2)){ affected.ApplyEffect(DamageType.FIRE); if((a != null && affected.actor() == a) || affected == t){ break; } } } if(a != null){ pos target_original_position = a.p; if(a.HasAttr(AttrType.IMMUNE_ARROWS)){ B.Add("The arrow sticks out ineffectively from " + a.the_name + ". ",a); } else{ if(a.magic_trinkets.Contains(MagicTrinketType.BRACERS_OF_ARROW_DEFLECTION)){ B.Add(a.You("deflect") + " the arrow! ",a); } else{ if(blocked_by_armor_miss){ B.Add(a.YourVisible() + " armor blocks the arrow. ",a); } else{ if(blocked_by_root_shell_miss){ B.Add(a.YourVisible() + " root shell blocks the arrow. ",a); } else{ bool alive = true; bool crit = false; int crit_chance = 8; //base crit rate is 1/8 if(a.EquippedArmor != null && (a.EquippedArmor.status[EquipmentStatus.WEAK_POINT] || a.EquippedArmor.status[EquipmentStatus.DAMAGED] || a.HasAttr(AttrType.SWITCHING_ARMOR))){ crit_chance /= 2; } if(a.HasAttr(AttrType.SUSCEPTIBLE_TO_CRITS)){ crit_chance /= 2; } if(Bow != null && Bow.enchantment == EnchantmentType.PRECISION && !Bow.status[EquipmentStatus.NEGATED]){ crit_chance /= 2; } if(crit_chance <= 1 || R.OneIn(crit_chance)){ crit = true; } if(this == player && IsHiddenFrom(a) && crit && !a.HasAttr(AttrType.NONLIVING,AttrType.PLANTLIKE,AttrType.BOSS_MONSTER) && a.type != ActorType.CYCLOPEAN_TITAN){ //none of the bow-wielding monsters should ever be hidden from the player B.Add(a.the_name + " falls with your arrow between the eyes. ",a); //B.Add("Headshot! ",a); a.Kill(); alive = false; } else{ B.Add("The arrow hits " + a.the_name + ". ",a); if(!a.TakeDamage(DamageType.NORMAL,DamageClass.PHYSICAL,R.Roll(2,6)+TotalSkill(SkillType.COMBAT),this,a_name + "'s arrow")){ alive = false; } if(crit && alive){ if(a.type == ActorType.CYCLOPEAN_TITAN){ if(!a.HasAttr(AttrType.COOLDOWN_1)){ B.Add(YourVisible() + " arrow pierces its eye, blinding it! ",this,a); Q.KillEvents(a,AttrType.BLIND); a.attrs[AttrType.BLIND] = 1; a.attrs[AttrType.COOLDOWN_1] = 1; } } else{ Event e = Q.FindAttrEvent(a,AttrType.IMMOBILE); if(!a.HasAttr(AttrType.IMMOBILE) || (e != null && e.msg.Contains("no longer pinned"))){ //i.e. don't pin naturally immobile monsters //todo - new refreshduration implementation should allow this to be done more naturally B.Add(a.YouAre() + " pinned! ",a); a.RefreshDuration(AttrType.IMMOBILE,100,a.YouAre() + " no longer pinned. ",a); if(a.HasAttr(AttrType.FLYING) && a.tile().IsTrap()){ a.tile().TriggerTrap(); } } } } if(alive && a.HasAttr(AttrType.NONLIVING)){ if(Bow != null && Bow.enchantment == EnchantmentType.DISRUPTION && !Bow.status[EquipmentStatus.NEGATED]){ B.Add(a.YouAre() + " disrupted! ",a); if(!a.TakeDamage(DamageType.MAGIC,DamageClass.MAGICAL,a.maxhp / 5,this)){ alive = false; } } } if(alive && !a.HasAttr(AttrType.IMMUNE_COLD)){ if(Bow != null && Bow.enchantment == EnchantmentType.CHILLING && !Bow.status[EquipmentStatus.NEGATED]){ B.Add(a.YouAre() + " chilled. ",a); if(!a.HasAttr(AttrType.CHILLED)){ a.attrs[AttrType.CHILLED] = 1; } else{ a.attrs[AttrType.CHILLED] *= 2; } if(!a.TakeDamage(DamageType.COLD,DamageClass.MAGICAL,a.attrs[AttrType.CHILLED],this)){ alive = false; } } } if(alive && flaming_arrow_start != -1){ a.ApplyBurning(); } } if(!alive && Bow != null && Bow.enchantment == EnchantmentType.VICTORY && !Bow.status[EquipmentStatus.NEGATED]){ curhp += 5; if(curhp > maxhp){ curhp = maxhp; } } } } } } if(Bow != null && Bow.enchantment == EnchantmentType.ECHOES && !Bow.status[EquipmentStatus.NEGATED]){ List<Tile> line2 = line.From(M.tile[target_original_position]); if(line2.Count > 1){ FireArrow(line2,true); //todo: does this need special handling? should a burning monster cause a flaming echo? } } } else{ if(!no_terrain_collision_message || t.Is(TileType.POISON_BULB) || (t.Is(TileType.WAX_WALL) && flaming_arrow_start != -1)){ B.Add("The arrow hits " + t.the_name + ". ",t); if(t.Is(TileType.POISON_BULB)){ t.Bump(DirectionOf(t)); } if(flaming_arrow_start != -1){ t.ApplyEffect(DamageType.FIRE); } } } if(!free_attack){ Q1(); } }