Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add utility commands (info, kick, quickstart) #71

Open
wants to merge 39 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
e9f2804
start migration to builtin command system
Tran-Antoine Jun 17, 2021
9e613bc
delete old command
Tran-Antoine Jun 17, 2021
6e92dde
solve problems with migration
Tran-Antoine Jun 22, 2021
8d788fc
make slash commands work
Tran-Antoine Jul 7, 2021
dc9ecfd
minor fix
Tran-Antoine Jul 7, 2021
8526899
start to work on simple info command
Tran-Antoine Jul 7, 2021
3edb885
more work on info command and minor improvements
Tran-Antoine Jul 8, 2021
e6a0ee4
token fix
Tran-Antoine Jul 8, 2021
47ba2fe
resolve conflicts
Tran-Antoine Sep 20, 2021
432cbd7
implement quickstart command to avoid round config
Tran-Antoine Dec 12, 2021
2250cf3
fix conflicts with command system
Tran-Antoine Dec 12, 2021
4493dbe
fix commands
Tran-Antoine Dec 12, 2021
3384cdf
Merge branch 'master' of github.com:Tran-Antoine/sphinx into more-com…
Tran-Antoine Dec 12, 2021
5ee7009
add check
Tran-Antoine Dec 12, 2021
c38bb2a
start working on the weekly event
Tran-Antoine Feb 12, 2022
9499c78
finish non fixed player list system
Tran-Antoine Feb 12, 2022
0d1898e
remove error from counter limiter
Tran-Antoine Feb 12, 2022
c57b4c2
add weekly command
Tran-Antoine Feb 12, 2022
ceeaaac
add discord resources
Tran-Antoine Feb 12, 2022
ddbb1a6
fix encoding
Tran-Antoine Feb 16, 2022
68ea933
add time shortener
Tran-Antoine Feb 16, 2022
cde8e83
fix commented line
Tran-Antoine Feb 16, 2022
8645ff8
minor changes
Tran-Antoine Feb 16, 2022
2ec578a
update event question set
Tran-Antoine Feb 16, 2022
b339579
add resources
Tran-Antoine Feb 17, 2022
ee3b795
uncomment line
Tran-Antoine Feb 17, 2022
81841e9
update question sets for week 1 and 2
Tran-Antoine Feb 20, 2022
e0ca1f8
fix time restriction
Tran-Antoine Feb 20, 2022
26ae5a2
fix timezone
Tran-Antoine Feb 20, 2022
0172a4c
assign channels to games
Tran-Antoine Feb 20, 2022
bdcec4a
add question set for actual week 2
Tran-Antoine Feb 26, 2022
c88c7ed
fix difficulty
Tran-Antoine Feb 28, 2022
b4e96b0
update week number
Tran-Antoine Mar 6, 2022
5d6bd99
feat: add ?next instruction at end of round (#74)
MichelDucartier Mar 12, 2022
8142b2c
Merge branch 'more-commands' of github.com:Tran-Antoine/sphinx into m…
Tran-Antoine Mar 12, 2022
fdf54f6
fix boolean issue
Tran-Antoine Mar 12, 2022
daf2395
Fix NPE bug and add week4 questions
Tran-Antoine Mar 13, 2022
1642ce3
Fix question length
Tran-Antoine Mar 14, 2022
c82d145
add week5 questions
Tran-Antoine Mar 29, 2022
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
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,4 @@
*.sphinx
build
out
discord-impl/src/main/resources/token.txt
api/src/main/resources
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import net.starype.quiz.api.util.CheckSum;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Set;

Expand Down Expand Up @@ -38,7 +39,7 @@ public CheckSum computeCheckSum() {

@Override
public Set<DatabaseEntry> generateNewEntries(DatabaseEntryFactory factory) {
String text = new String(data);
String text = new String(data, StandardCharsets.UTF_8);
return QuestionParser.getDatabaseEntries(text, factory);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,9 @@ public void runAllEvents() {
this.lastMillis = currentTime;
eventsList.forEach((updatable -> updatable.update(deltaMillis)));
}

@Override
public void reset() {
this.lastMillis = System.currentTimeMillis();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,11 @@ public interface UpdatableHandler {
* @see Updatable
*/
void runAllEvents();

/**
* Resets the last millis value.
* Should be called at the beginning of each new round, since delta times are not calculated between rounds
* and would thus cause a huge time gap at the beginning of each round.
*/
void reset();
}
4 changes: 4 additions & 0 deletions api/src/main/java/net/starype/quiz/api/game/GuessCounter.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,8 @@ public int getPlayerGuess(IDHolder<?> holder) {
public boolean maxReached(IDHolder<?> holder) {
return getPlayerGuess(holder) < maxGuesses;
}

public boolean isEmpty() {
return guessesPerPlayer.isEmpty();
}
}
28 changes: 26 additions & 2 deletions api/src/main/java/net/starype/quiz/api/game/QuizTimer.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,22 @@
import java.time.Instant;
import java.util.concurrent.TimeUnit;

public class QuizTimer extends GameUpdatable {
public class QuizTimer extends GameUpdatable implements EventListener {
private long time;
private TimeUnit unit;
private final long shortenedTime;
private final TimeUnit unit;
private Instant startingInstant;
private Instant currentInstant;
private UpdatableHandler updatableHandler;

public QuizTimer(TimeUnit unit, long time) {
this(unit, time, time);
}

public QuizTimer(TimeUnit unit, long time, long shortenedTime) {
this.unit = unit;
this.time = time;
this.shortenedTime = shortenedTime;
}

@Override
Expand All @@ -37,7 +43,25 @@ public void update(long deltaMillis) {
}
}

@Override
public void shutDown() {
updatableHandler.unregisterEvent(this);
}

public long millisLeft() {
return unit.toMillis(time) - Duration.between(startingInstant, currentInstant).toMillis();
}

private void shortenRemaining() {
if(millisLeft() < unit.toMillis(shortenedTime)) {
return;
}
this.time = shortenedTime;
this.startingInstant = Instant.now();
}

@Override
public void onNotified() {
shortenRemaining();
}
}
15 changes: 10 additions & 5 deletions api/src/main/java/net/starype/quiz/api/game/SimpleGame.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@
public class SimpleGame<T extends QuizGame> implements QuizGame {

private ServerGate<T> gate;
private Queue<? extends QuizRound> rounds;
private Collection<? extends Player<?>> players;
private final Queue<? extends QuizRound> rounds;
private final Collection<? extends Player<?>> players;
private final AtomicBoolean paused;
private boolean waitingForNextRound;
private UpdatableHandler updatableHandler = new GameUpdatableHandler();
private final UpdatableHandler updatableHandler = new GameUpdatableHandler();
private boolean over;

public SimpleGame(Queue<? extends QuizRound> rounds, Collection<? extends Player<?>> players) {
Expand Down Expand Up @@ -96,7 +96,9 @@ public boolean nextRound() {
return true;
}

waitingForNextRound = false;
paused.set(false);
updatableHandler.reset();
startHead(false);
return true;
}
Expand Down Expand Up @@ -215,6 +217,9 @@ public void removePlayer(Object playerId) {
.filter(player -> player.getId().equals(playerId))
.findAny();
optPlayer.ifPresent(players::remove);
if(!rounds.isEmpty() && !paused.get()) {
rounds.element().checkEndOfRound();
}
}

@Override
Expand All @@ -237,8 +242,8 @@ private Player<?> findHolder(Object id) {
.orElseThrow(error);
}

protected Collection<? extends Player<?>> getPlayers() {
return players;
protected QuizRound getCurrentRound() {
return rounds.peek();
}

public boolean isWaitingForNextRound() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public static Question parse(ReadableRawMap config) {
return new DefaultQuestion.Builder()
.withAnswerEvaluator(evaluator)
.withRawText(rawText)
.withRawAnswer(String.join(",", rawAnswers))
.withRawAnswer(String.join(", ", rawAnswers))
.withTags(tags)
.withDifficulty(difficulty)
.build();
Expand Down
10 changes: 5 additions & 5 deletions api/src/main/java/net/starype/quiz/api/player/Player.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@

public class Player<T> implements IDHolder<T>, Comparable<Player<?>> {

private String username;
private String nickname;
private Score score;
private T id;
private Collection<Player<?>> children = new ArrayList<>();
private final String username;
private final String nickname;
private final Score score;
private final T id;
private final Collection<Player<?>> children = new ArrayList<>();

public Player(T id, String username, String nickname) {
this.username = username;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public QuizRound create(Question question, int maxGuesses,
.addEvent(quizTimer)
.withEndingCondition(timeOutEnding)
.withPlayerEligibility(new MaxGuess(counter))
.addEvent(quizTimer)
.build();

quizTimer.addEventListener(round::checkEndOfRound);
Expand Down
4 changes: 2 additions & 2 deletions api/src/main/java/net/starype/quiz/api/server/ServerGate.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
*/
public class ServerGate<T extends QuizGame> {

private GameServer<? super T> server;
private T game;
private final GameServer<? super T> server;
private final T game;

/**
* Initialize a gate with the given server and no game.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public void execute(CommandContext context) {
Map<Supplier<Boolean>, String> stopConditions = createStopConditions(
context.getGameList(),
context.getLobbyList(),
playerId,
author,
author.getEffectiveName());

Message message = context.getMessage();
Expand All @@ -42,19 +42,19 @@ public void execute(CommandContext context) {
}

private Map<Supplier<Boolean>, String> createStopConditions(
GameList gameList, LobbyList lobbyList, String authorId, String nickName) {
GameList gameList, LobbyList lobbyList, Member author, String nickName) {

Map<Supplier<Boolean>, String> conditions = new LinkedHashMap<>();
conditions.put(
() -> lobbyList.findByPlayer(authorId).isPresent(),
() -> lobbyList.findByPlayer(author.getId()).isPresent(),
nickName + ", you are already in a lobby");

conditions.put(
() -> gameList.isPlaying(authorId),
() -> gameList.isPlaying(author),
nickName + ", you are already playing a game");

conditions.put(
() -> !lobbyLimiter.register(authorId.hashCode()),
() -> !lobbyLimiter.register(author.hashCode()),
"Error: Cannot create a new lobby as the maximum number of lobbies has been reached");


Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package net.starype.quiz.discordimpl.command;

import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.starype.quiz.discordimpl.game.DiscordQuizGame;
import net.starype.quiz.discordimpl.game.GameList;
Expand All @@ -12,28 +13,31 @@ public class ForceNextRoundCommand implements QuizCommand {
@Override
public void execute(CommandContext context) {
GameList gameList = context.getGameList();
String playerId = context.getAuthor().getId();
Member player = context.getAuthor();
Message message = context.getMessage();

Map<Supplier<Boolean>, String> conditions = createStopConditions(gameList, playerId);
Map<Supplier<Boolean>, String> conditions = createStopConditions(gameList, player);

if(StopConditions.shouldStop(conditions, context.getChannel(), message)) {
return;
}

DiscordQuizGame game = gameList.getFromPlayer(playerId).get();
DiscordQuizGame game = gameList.getFromPlayer(player).get();
game.addLog(message.getId());
game.nextRound();
message.addReaction("\uD83D\uDC4D").queue();
}

public static Map<Supplier<Boolean>, String> createStopConditions(GameList gameList, String authorId) {
public static Map<Supplier<Boolean>, String> createStopConditions(GameList gameList, Member author) {
Map<Supplier<Boolean>, String> conditions = NextRoundCommand.createStopConditions(
gameList,
authorId
author
);
conditions.put(
() -> !gameList.getFromPlayer(authorId).get().isAuthor(authorId),
() -> gameList.getFromPlayer(author).isEmpty(),
"You need to be in a game to use this");
conditions.put(
() -> !gameList.getFromPlayer(author).get().isAuthor(author.getId()),
"Only the game creator can use this command");
return conditions;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public void execute(CommandContext context) {
}

private static Optional<InputStream> generateFile(String urlName, TextChannel channel) {
Collection<? extends EntryUpdater> updaters = InputUtils.loadEntryUpdaters(urlName, channel);
Collection<? extends EntryUpdater> updaters = InputUtils.loadEntryUpdatersFromUrl(urlName, channel);
AtomicReference<ByteBuffer> output = new AtomicReference<>();
SerializedIO serializedIO = new ByteSerializedIO(new byte[0], output);
TrackedDatabase db = new QuestionDatabase(updaters, serializedIO, false);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package net.starype.quiz.discordimpl.command;

import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.TextChannel;
import net.starype.quiz.discordimpl.game.DiscordQuizGame;
import net.starype.quiz.discordimpl.game.GameList;
import net.starype.quiz.discordimpl.game.GameLobby;
import net.starype.quiz.discordimpl.game.LobbyList;
import net.starype.quiz.discordimpl.util.MessageUtils;

import java.awt.*;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;

public class InfoCommand implements QuizCommand {

@Override
public void execute(CommandContext context) {

GameList gameList = context.getGameList();
LobbyList lobbyList = context.getLobbyList();
TextChannel channel = context.getChannel();
Member member = context.getAuthor();

Map<Supplier<Boolean>, String> conditions = createStopConditions(lobbyList, gameList, member);
if(StopConditions.shouldStop(conditions, channel, context.getMessage())) {
return;
}

Optional<GameLobby> lobby = lobbyList.findByPlayer(member.getId());
if(lobby.isPresent()) {
displayLobbyInfo(lobby.get(), channel);
} else {
displayGameInfo(gameList.getFromPlayer(member).get(), channel);
}
}

private static void displayLobbyInfo(GameLobby lobby, TextChannel channel) {
EmbedBuilder builder = new EmbedBuilder();
builder.setColor(Color.CYAN);

builder.addField("lobby ID", lobby.getName(), false);
builder.addBlankField(false);
builder.addField("Players", String.join(", ", lobby.retrieveNames()), false);
builder.addField("Question count", String.valueOf(lobby.questionCount()), false);

MessageUtils.sendAndTrack(builder.build(), channel, lobby);
}

private static void displayGameInfo(DiscordQuizGame game, TextChannel channel) {
EmbedBuilder builder = new EmbedBuilder();
builder.setColor(Color.ORANGE);

if(game.isOutOfRounds() && game.isWaitingForNextRound()) {
builder.addField("Game Status", "Waiting to display results", false);
builder.addBlankField(false);
builder.addField("Not ready yet", String.join(", ", game.haveNotVoted()), false);
}
else if(!game.hasRoundStarted()) {
builder.addField("Game Status", "Waiting for next round", false);
builder.addBlankField(false);
builder.addField("Not ready yet", String.join(", ", game.haveNotVoted()), false);
} else if(!game.isCurrentRoundFinished()){
builder.addField("Game Status", "Round in progress", false);
builder.addBlankField(false);
builder.addField("Waiting for", String.join(", ", game.waitingFor()), false);
builder.addField("Have answered", String.join(", ", game.haveAnswered()), false);
}

channel.sendMessageEmbeds(builder.build())
.map(Message::getId)
.queue(game::addLog);
}

private static Map<Supplier<Boolean>, String> createStopConditions(LobbyList lobbyList, GameList gameList, Member author) {
Map<Supplier<Boolean>, String> conditions = new LinkedHashMap<>();
conditions.put(
() -> lobbyList.findByPlayer(author.getId()).isEmpty() && gameList.getFromPlayer(author).isEmpty(),
"You must belong to either a lobby or a game");
return conditions;
}

@Override
public String getName() {
return "info";
}

@Override
public String getDescription() {
return "Get relevant information on your lobby/game";
}
}
Loading