Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Callvote.API/Features/Votes/UserIndentifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,21 +51,21 @@ public UserIndentifier(int userId, string name, string uniqueId)
/// <param name="left">The first <see cref="UserIndentifier"/> instance to compare.</param>
/// <param name="right">The second <see cref="UserIndentifier"/> instance to compare.</param>
/// <returns>true if the two <see cref="UserIndentifier"/> instances are equal; otherwise, false.</returns>
public static bool operator ==(UserIndentifier left, UserIndentifier right) => left.Equals(right);
public static bool operator ==(UserIndentifier left, UserIndentifier right) => (left == null || right == null) && left.Equals(right);

/// <summary>
/// Determines whether two instances of the <see cref="UserIndentifier"/> class are not equal.
/// </summary>
/// <param name="left">The first <see cref="UserIndentifier"/> instance to compare.</param>
/// <param name="right">The second <see cref="UserIndentifier"/> instance to compare.</param>
/// <returns>true if the two <see cref="UserIndentifier"/> instances not are equal; otherwise, false.</returns>
public static bool operator !=(UserIndentifier left, UserIndentifier right) => !left.Equals(right);
public static bool operator !=(UserIndentifier left, UserIndentifier right) => (left == null || right == null) && !left.Equals(right);

/// <inheritdoc/>
public bool Equals(UserIndentifier other) => this.UniqueUserId == other.UniqueUserId && this.UserId == other.UserId;
public override bool Equals(object obj) => obj is UserIndentifier other && this.Equals(other);

/// <inheritdoc/>
public override bool Equals(object obj) => obj is UserIndentifier other && this.Equals(other);
public bool Equals(UserIndentifier other) => other is not null && this.UniqueUserId == other.UniqueUserId;

/// <inheritdoc/>
public override int GetHashCode() => this.UniqueUserId.GetHashCode();
Expand Down
42 changes: 40 additions & 2 deletions Callvote.API/Features/Votes/Vote.cs
Original file line number Diff line number Diff line change
Expand Up @@ -432,19 +432,57 @@ public virtual string BuildResultsMessage()
/// <summary>
/// Starts the <see cref="Vote"/> by registering the commands and starting the coroutine.
/// </summary>
internal void StartVote()
/// <returns>Returns the <see cref="CallVoteStatus"/>.</returns>
internal CallVoteStatus StartVote()
{
CallingVoteEventArgs e = new(this);
EventsHandlers.OnCallingVote(e);
if (!e.IsAllowed)
{
return CallVoteStatus.VoteCancelled;
}

this.RegisterAllVoteOptions();
this.StartVoteCoroutine();

CalledVoteEventArgs ev = new(this);
EventsHandlers.OnCalledVote(ev);
return CallVoteStatus.VoteStarted;
}

/// <summary>
/// Stops the <see cref="Vote"/> by unregistering the command and stopping the coroutine.
/// </summary>
internal void FinishVote()
/// <param name="isForced">If the voting will display the results message or invoke the Callback.</param>
internal void FinishVote(bool isForced = false)
{
VoteEndingEventArgs e = new(this);
if (!e.IsAllowed)
{
return;
}

this.UnregisterVoteOptionsCommand();
this.StopVoteCoroutine();

if (!isForced)
{
return;
}

if (this.Callback == null)
{
DisplayHandler.Show(this.ResultsMessageDuration, this.BuildResultsMessage(), this.AllowedPlayers);
}
else
{
this?.Callback.Invoke(this);
}

// Prevents being null when it's later used in the event
Vote vote = this;
VoteEndedEventArgs ev = new(vote);
EventsHandlers.OnVoteEnded(ev);
}

/// <summary>
Expand Down
108 changes: 77 additions & 31 deletions Callvote.API/Features/Votes/VoteHandler.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Callvote.API.Enums;
using Callvote.API.Events;
using Callvote.API.Events.EventArgs;
using Callvote.API.Features.Displays;
using Utils.NonAllocLINQ;

namespace Callvote.API.Features.Votes
{
Expand All @@ -23,6 +23,10 @@ static VoteHandler()
}
#endif

public static IReadOnlyCollection<Vote> ReadOnlyActiveParallelVotes => ActiveParallelVotes;

internal static HashSet<Vote> ActiveParallelVotes { get; } = new HashSet<Vote>();

/// <summary>
/// Gets the currently active <see cref="Vote"/> instance. Null when no vote is in progress.
/// </summary>
Expand All @@ -43,28 +47,25 @@ static VoteHandler()
/// If queueing is enabled the <paramref name="vote"/> will be enqueued and the <see cref="Vote"/> is started immediately.
/// </summary>
/// <param name="vote">The <see cref="Vote"/> to start or enqueue.</param>
/// <param name="isParallel">If the vote will be ran in parallel.</param>
/// <returns>A <see cref="CallVoteStatus"/> representing if the action was sucessfull, or for example, if the queue is full.</returns>
public static CallVoteStatus CallVote(Vote vote)
public static CallVoteStatus CallVote(Vote vote, bool isParallel = false)
{
if (vote == null)
{
throw new ArgumentNullException(nameof(vote), "Vote cannot be null!");
}

if (!IsVoteActive)
if (isParallel)
{
CallingVoteEventArgs e = new(vote);
EventsHandlers.OnCallingVote(e);
if (!e.IsAllowed)
{
return CallVoteStatus.VoteCancelled;
}
ActiveParallelVotes.Add(vote);
return CurrentVote.StartVote();
}

if (!IsVoteActive)
{
CurrentVote = vote;
CurrentVote.StartVote();
CalledVoteEventArgs ev = new(CurrentVote);
EventsHandlers.OnCalledVote(ev);
return CallVoteStatus.VoteStarted;
return CurrentVote.StartVote();
}

return CallVoteStatus.VoteInProgress;
Expand All @@ -82,31 +83,76 @@ public static void FinishVote(bool isForced = false)
return;
}

VoteEndingEventArgs e = new(CurrentVote);
if (!e.IsAllowed)
CurrentVote?.FinishVote(isForced);

CurrentVote = null;
}

public static void StopParallelVote(Vote vote, bool isForced = false)
{
if (vote == null)
{
return;
}

if (!ActiveParallelVotes.Contains(vote) && !vote.IsCoroutineActive)
{
return;
}

CurrentVote?.FinishVote();
CurrentVote?.FinishVote(isForced);
ActiveParallelVotes.Remove(vote);
}

public static void StopParallelVote(long voteId, bool isForced = false)
{
if (voteId == 0)
{
return;
}

if (!isForced)
if (!ActiveParallelVotes.TryGetFirst(v => v.VoteId == voteId, out Vote vote))
{
if (CurrentVote?.Callback == null)
{
DisplayHandler.Show(CurrentVote.ResultsMessageDuration, CurrentVote.BuildResultsMessage(), CurrentVote.AllowedPlayers);
}
else
{
CurrentVote?.Callback.Invoke(CurrentVote);
}
return;
}

Vote vote = CurrentVote;
CurrentVote = null;
StopParallelVote(vote, isForced);
}

public static void StopParallelVotes(UserIndentifier user, bool isForced = false)
{
if (user == null)
{
return;
}

foreach (Vote vote in ActiveParallelVotes.Where(v => v.CallVotePlayer == user))
{
StopParallelVote(vote, isForced);
}
}

public static void StopParallelVotes(IEnumerable<Vote> votes, bool isForced = false)
{
if (votes == null)
{
return;
}

foreach (Vote vote in votes)
{
StopParallelVote(vote, isForced);
}
}

public static void StopAllParallelVotes(bool isForced = false)
{
foreach (Vote vote in ActiveParallelVotes)
{
StopParallelVote(vote, isForced);
}

VoteEndedEventArgs ev = new(vote);
EventsHandlers.OnVoteEnded(ev);
ActiveParallelVotes.Clear();
}

/// <summary>
Expand Down