This repository has been archived by the owner on Jan 12, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 65
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #12 from Webbanditten/feature/infobus-poll
Feature/infobus poll
- Loading branch information
Showing
13 changed files
with
426 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
112 changes: 112 additions & 0 deletions
112
Kepler-Server/src/main/java/org/alexdev/kepler/game/commands/registered/InfobusCommand.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package org.alexdev.kepler.game.commands.registered; | ||
|
||
import org.alexdev.kepler.game.commands.Command; | ||
import org.alexdev.kepler.game.entity.Entity; | ||
import org.alexdev.kepler.game.entity.EntityType; | ||
import org.alexdev.kepler.game.fuserights.Fuseright; | ||
import org.alexdev.kepler.game.infobus.InfobusManager; | ||
import org.alexdev.kepler.game.player.Player; | ||
import org.alexdev.kepler.game.room.Room; | ||
import org.alexdev.kepler.messages.outgoing.rooms.user.CHAT_MESSAGE; | ||
import org.alexdev.kepler.messages.outgoing.user.ALERT; | ||
import org.alexdev.kepler.util.StringUtil; | ||
import org.apache.commons.lang3.math.NumberUtils; | ||
|
||
import java.util.stream.IntStream; | ||
|
||
public class InfobusCommand extends Command { | ||
@Override | ||
public void addPermissions() { | ||
this.permissions.add(Fuseright.ADMINISTRATOR_ACCESS); | ||
} | ||
|
||
@Override | ||
public void addArguments() { | ||
this.arguments.add("subcommand"); | ||
} | ||
|
||
@Override | ||
public void handleCommand(Entity entity, String message, String[] args) { | ||
|
||
if (entity.getType() != EntityType.PLAYER) { | ||
return; | ||
} | ||
|
||
Player player = (Player) entity; | ||
|
||
if (player.getRoomUser().getRoom() == null) { | ||
return; | ||
} | ||
|
||
Room room = player.getRoomUser().getRoom(); | ||
InfobusManager bus = InfobusManager.getInstance(); | ||
|
||
|
||
if(args[0].equalsIgnoreCase("status")) { | ||
player.send(new ALERT(bus.constructStatus())); | ||
} | ||
|
||
if(args[0].equalsIgnoreCase("start")) { | ||
if(bus.getQuestion() != null && !bus.getQuestion().isEmpty()) { | ||
System.out.println("Question is not empty"); | ||
if(bus.getOptions().size() > 0) { | ||
System.out.println("Starting"); | ||
bus.startPoll(); | ||
} else { | ||
player.send(new CHAT_MESSAGE(CHAT_MESSAGE.ChatMessageType.WHISPER, player.getRoomUser().getInstanceId(), "You need to add some options for the question: :infobus option [add/remove] [option]")); | ||
} | ||
} else { | ||
player.send(new CHAT_MESSAGE(CHAT_MESSAGE.ChatMessageType.WHISPER, player.getRoomUser().getInstanceId(), "You need to set a question: :infobus question [question]")); | ||
} | ||
} | ||
|
||
if(args[0].equalsIgnoreCase("reset")) { | ||
player.send(new CHAT_MESSAGE(CHAT_MESSAGE.ChatMessageType.WHISPER, player.getRoomUser().getInstanceId(), "Reset question, options and votes.")); | ||
bus.reset(); | ||
} | ||
|
||
if(args[0].equalsIgnoreCase("question")) { | ||
String question = StringUtil.filterInput(String.join(" ", IntStream.range(1, args.length).mapToObj(i -> args[i]).toArray(String[]::new)), true); | ||
player.send(new CHAT_MESSAGE(CHAT_MESSAGE.ChatMessageType.WHISPER, player.getRoomUser().getInstanceId(), "Infobus question is now: " + question)); | ||
bus.setQuestion(question); | ||
} | ||
|
||
if(args[0].equalsIgnoreCase("option") && args[1].equalsIgnoreCase("add")) { | ||
|
||
if(args[2] == null) { | ||
player.send(new CHAT_MESSAGE(CHAT_MESSAGE.ChatMessageType.WHISPER, player.getRoomUser().getInstanceId(), "You're missing option text")); | ||
} | ||
|
||
String option = StringUtil.filterInput(String.join(" ", IntStream.range(2, args.length).mapToObj(i -> args[i]).toArray(String[]::new)), true); | ||
bus.addOption(option); | ||
player.send(new CHAT_MESSAGE(CHAT_MESSAGE.ChatMessageType.WHISPER, player.getRoomUser().getInstanceId(), "Added option to the question, see the status by executing :infobus status")); | ||
|
||
} else if(args[0].equalsIgnoreCase("option") && args[1].equalsIgnoreCase("remove")) { | ||
|
||
if(!NumberUtils.isCreatable(args[2])) { | ||
player.send(new CHAT_MESSAGE(CHAT_MESSAGE.ChatMessageType.WHISPER, player.getRoomUser().getInstanceId(), "To remove a question you need to the number found in :infobus status.")); | ||
} else { | ||
bus.removeOption(Integer.parseInt(args[2])); | ||
player.send(new CHAT_MESSAGE(CHAT_MESSAGE.ChatMessageType.WHISPER, player.getRoomUser().getInstanceId(), "Removed option from the question, see the status by executing :infobus status")); | ||
} | ||
|
||
} else if(args[0].equalsIgnoreCase("option") && args[1].isEmpty()) { | ||
player.send(new CHAT_MESSAGE(CHAT_MESSAGE.ChatMessageType.WHISPER, player.getRoomUser().getInstanceId(), "Usage: :infobus option [add/remove] [option]")); | ||
} | ||
|
||
if(args[0].equalsIgnoreCase("close")) { | ||
player.send(new CHAT_MESSAGE(CHAT_MESSAGE.ChatMessageType.WHISPER, player.getRoomUser().getInstanceId(), "Info-bus door closed.")); | ||
InfobusManager.getInstance().closeDoor(room); | ||
} | ||
|
||
if(args[0].equalsIgnoreCase("open")) { | ||
player.send(new CHAT_MESSAGE(CHAT_MESSAGE.ChatMessageType.WHISPER, player.getRoomUser().getInstanceId(), "Info-bus door opened.")); | ||
InfobusManager.getInstance().openDoor(room); | ||
} | ||
} | ||
|
||
@Override | ||
public String getDescription() { | ||
return "<subcommand> (open,close,question,option,reset,status) "; | ||
} | ||
} |
185 changes: 185 additions & 0 deletions
185
Kepler-Server/src/main/java/org/alexdev/kepler/game/infobus/InfobusManager.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
package org.alexdev.kepler.game.infobus; | ||
|
||
|
||
import org.alexdev.kepler.game.GameScheduler; | ||
import org.alexdev.kepler.game.player.PlayerManager; | ||
import org.alexdev.kepler.game.room.Room; | ||
import org.alexdev.kepler.log.Log; | ||
import org.alexdev.kepler.messages.outgoing.rooms.infobus.VOTE_QUESTION; | ||
import org.alexdev.kepler.messages.outgoing.rooms.infobus.VOTE_RESULTS; | ||
import org.alexdev.kepler.messages.outgoing.rooms.items.SHOWPROGRAM; | ||
import org.alexdev.kepler.util.schedule.FutureRunnable; | ||
|
||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.concurrent.CopyOnWriteArrayList; | ||
import java.util.concurrent.TimeUnit; | ||
import java.util.concurrent.atomic.AtomicInteger; | ||
|
||
public class InfobusManager { | ||
private static InfobusManager instance; | ||
private boolean isDoorOpen; | ||
private List<Integer> playersInBus; | ||
private FutureRunnable gameTimerRunnable; | ||
private AtomicInteger pollTimeLeft; | ||
private String question; | ||
private List<String> options; | ||
private List<Integer> votes; | ||
|
||
|
||
public static InfobusManager getInstance() { | ||
if (instance == null) { | ||
instance = new InfobusManager(); | ||
} | ||
|
||
return instance; | ||
} | ||
|
||
InfobusManager() { | ||
this.question = null; | ||
this.playersInBus = new CopyOnWriteArrayList<>(); | ||
this.options = new CopyOnWriteArrayList<>(); | ||
this.votes = new CopyOnWriteArrayList<>(); | ||
} | ||
|
||
private int getVotes(int optionIndex) | ||
{ | ||
return Collections.frequency(this.votes, optionIndex); | ||
} | ||
|
||
public void startPoll() { | ||
this.pollTimeLeft = new AtomicInteger(30); | ||
this.gameTimerRunnable = new FutureRunnable() { | ||
public void run() { | ||
try { | ||
if (pollTimeLeft.getAndDecrement() == 0) { | ||
this.cancelFuture(); | ||
pollEnded(); | ||
} | ||
} catch (Exception ex) { | ||
Log.getErrorLogger().error("Error occurred in infobus runnable: ", ex); | ||
} | ||
} | ||
}; | ||
|
||
var future = GameScheduler.getInstance().getService().scheduleAtFixedRate(this.gameTimerRunnable, 0, 1, TimeUnit.SECONDS); | ||
this.gameTimerRunnable.setFuture(future); | ||
|
||
// Send question to players in infobus | ||
for (int playerId : this.getPlayers()) { | ||
PlayerManager.getInstance().getPlayerById(playerId).send(new VOTE_QUESTION(constructVoteQuestion())); | ||
} | ||
} | ||
|
||
// Constructs the string shown in the status modal | ||
public String constructStatus() { | ||
StringBuilder msg = new StringBuilder().append("Users in bus: " + this.playersInBus + "\r"); | ||
|
||
msg.append("\r Question: " + this.question); | ||
msg.append("\r Options: \r"); | ||
for(int i=0; i < options.size(); i++){ | ||
int optionNumber = i + 1; | ||
msg.append("\r" + optionNumber + ":" + options.get(i)); | ||
} | ||
return msg.toString(); | ||
} | ||
|
||
// Constructs the message sent to the client | ||
public String constructVoteQuestion() { | ||
StringBuilder msg = new StringBuilder().append(this.question); | ||
for(int i=0; i < options.size(); i++){ | ||
int optionNumber = i + 1; | ||
msg.append("\r" + optionNumber + ":" + options.get(i)); | ||
} | ||
return msg.toString(); | ||
} | ||
|
||
// Construct vote result | ||
public String constructVoteResult() { | ||
StringBuilder msg = new StringBuilder().append("/" + this.votes.size()); | ||
for(int i=0; i < options.size(); i++){ | ||
msg.append("/" + getVotes(i)); | ||
} | ||
|
||
return msg.toString(); | ||
} | ||
|
||
public void setQuestion(String question) { | ||
this.question = question; | ||
} | ||
|
||
public void addOption(String option) { | ||
this.options.add(option); | ||
} | ||
|
||
public void removeOption(int option) { | ||
// minus one, so it makes sense when using status | ||
if(this.options.indexOf(this.options.get(option-1)) != -1) { | ||
this.options.remove(this.options.get(option-1)); | ||
} | ||
} | ||
|
||
public void addVote(int option) { | ||
this.votes.add(option-1); | ||
} | ||
|
||
|
||
public void reset() { | ||
this.question = null; | ||
this.votes.clear(); | ||
this.options.clear(); | ||
} | ||
|
||
public void pollEnded() { | ||
for (int playerId : this.getPlayers()) { | ||
PlayerManager.getInstance().getPlayerById(playerId).send(new VOTE_RESULTS(constructVoteResult())); | ||
} | ||
|
||
this.reset(); | ||
} | ||
|
||
public String getQuestion() { | ||
return this.question; | ||
} | ||
|
||
public List<String> getOptions() { | ||
return this.options; | ||
} | ||
|
||
public List<Integer> getPlayers() { | ||
return this.playersInBus; | ||
} | ||
|
||
public boolean isDoorOpen() { | ||
return this.isDoorOpen; | ||
} | ||
|
||
public void openDoor(Room room) { | ||
this.isDoorOpen = true; | ||
room.send(new SHOWPROGRAM(new String[] { "bus", "open" })); | ||
} | ||
|
||
public void closeDoor(Room room) { | ||
this.isDoorOpen = false; | ||
room.send(new SHOWPROGRAM(new String[] { "bus", "close" })); | ||
} | ||
|
||
public int getDoorX() { | ||
return 28; | ||
} | ||
|
||
public int getDoorY() { | ||
return 4; | ||
} | ||
|
||
public void addPlayer(int player) { | ||
this.playersInBus.add(player); | ||
} | ||
|
||
public void removePlayer(int player) { | ||
if(this.playersInBus.indexOf(player) != -1) { | ||
this.playersInBus.remove(this.playersInBus.indexOf(player)); | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.