diff --git a/Commons/core/src/main/i18n/templates/pgm/PGMUI.properties b/Commons/core/src/main/i18n/templates/pgm/PGMUI.properties index 91c82afd7..59de625f1 100644 --- a/Commons/core/src/main/i18n/templates/pgm/PGMUI.properties +++ b/Commons/core/src/main/i18n/templates/pgm/PGMUI.properties @@ -352,3 +352,5 @@ stats.ui.cores = Cores Leaked: stats.ui.monuments = Monuments Destroyed: stats.ui.teamkills = TK: +autojoin.starting = You will join the match in {0} seconds. Left click the helmet to cancel! +autojoin.cancelled = You will now observe the match. Right click the helmet to join again! \ No newline at end of file diff --git a/PGM/src/main/java/tc/oc/pgm/PGMModulesManifest.java b/PGM/src/main/java/tc/oc/pgm/PGMModulesManifest.java index edc050fab..7c4eac13a 100644 --- a/PGM/src/main/java/tc/oc/pgm/PGMModulesManifest.java +++ b/PGM/src/main/java/tc/oc/pgm/PGMModulesManifest.java @@ -2,6 +2,7 @@ import tc.oc.commons.core.inject.HybridManifest; import tc.oc.pgm.animation.AnimationManifest; +import tc.oc.pgm.autojoin.AutoJoinManifest; import tc.oc.pgm.broadcast.BroadcastManifest; import tc.oc.pgm.classes.ClassManifest; import tc.oc.pgm.controlpoint.ControlPointManifest; @@ -42,6 +43,7 @@ public class PGMModulesManifest extends HybridManifest { @Override protected void configure() { + install(new AutoJoinManifest()); install(new FilterManifest()); install(new RegionManifest()); install(new KitManifest()); diff --git a/PGM/src/main/java/tc/oc/pgm/autojoin/AutoJoinManifest.java b/PGM/src/main/java/tc/oc/pgm/autojoin/AutoJoinManifest.java new file mode 100644 index 000000000..6211ca639 --- /dev/null +++ b/PGM/src/main/java/tc/oc/pgm/autojoin/AutoJoinManifest.java @@ -0,0 +1,13 @@ +package tc.oc.pgm.autojoin; + +import tc.oc.commons.bukkit.settings.SettingBinder; +import tc.oc.commons.core.inject.HybridManifest; +import tc.oc.pgm.match.inject.MatchModuleFixtureManifest; + +public class AutoJoinManifest extends HybridManifest { + @Override + protected void configure() { + new SettingBinder(publicBinder()).addBinding().toInstance(AutoJoinSetting.get()); + install(new MatchModuleFixtureManifest(){}); + } +} diff --git a/PGM/src/main/java/tc/oc/pgm/autojoin/AutoJoinMatchModule.java b/PGM/src/main/java/tc/oc/pgm/autojoin/AutoJoinMatchModule.java new file mode 100644 index 000000000..0ef82bce6 --- /dev/null +++ b/PGM/src/main/java/tc/oc/pgm/autojoin/AutoJoinMatchModule.java @@ -0,0 +1,81 @@ +package tc.oc.pgm.autojoin; + +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.stream.Stream; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import tc.oc.commons.bukkit.settings.SettingManagerProvider; +import tc.oc.pgm.events.ListenerScope; +import tc.oc.pgm.events.PlayerChangePartyEvent; +import tc.oc.pgm.join.JoinMatchModule; +import tc.oc.pgm.join.JoinMethod; +import tc.oc.pgm.match.MatchModule; +import tc.oc.pgm.match.MatchPlayer; +import tc.oc.pgm.match.MatchScope; + +import javax.inject.Inject; + +/** + * New join feature that allows players to join without interfacing with GUI + * with an AutoJoinSetting that allows players to use the legacy join feature + * instead. + */ +@ListenerScope(MatchScope.LOADED) +public class AutoJoinMatchModule extends MatchModule implements Listener { + private Set joiningPlayers; + private final SettingManagerProvider settingManagerProvider; + private final JoinMatchModule joinMatchModule; + + @Inject public AutoJoinMatchModule(SettingManagerProvider settingManagerProvider, JoinMatchModule joinMatchModule) { + this.joiningPlayers = new LinkedHashSet<>(); + this.settingManagerProvider = settingManagerProvider; + this.joinMatchModule = joinMatchModule; + } + + @Override + public void disable() { + joiningPlayers.clear(); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void playerJoin(final PlayerChangePartyEvent event) { + MatchPlayer player = event.getPlayer(); + + if(match.hasStarted()) return; + + if(event.getNewParty() == null) { + joiningPlayers.remove(player); + return; + } + + if(event.getNewParty().isParticipatingType()) return; + + if(joiningPlayers.contains(player)) return; + + if(!settingManagerProvider.getManager(player.getBukkit()).getValue(AutoJoinSetting.get(), Boolean.class, true)) return; + + joiningPlayers.add(player); + } + + public boolean shouldAutoJoin(MatchPlayer player) { + return joiningPlayers.contains(player); + } + + public void cancelAutojoin(MatchPlayer player) { + joiningPlayers.remove(player); + } + + public void requestJoin(MatchPlayer player) { + joinMatchModule.requestJoin(player, JoinMethod.USER); + } + + public void enterAllPlayers() { + if(!joiningPlayers.isEmpty()) joiningPlayers.forEach(this::requestJoin); + } + + public Stream joiningPlayers() { + return joiningPlayers.stream(); + } +} diff --git a/PGM/src/main/java/tc/oc/pgm/autojoin/AutoJoinSetting.java b/PGM/src/main/java/tc/oc/pgm/autojoin/AutoJoinSetting.java new file mode 100644 index 000000000..b4d2d1721 --- /dev/null +++ b/PGM/src/main/java/tc/oc/pgm/autojoin/AutoJoinSetting.java @@ -0,0 +1,18 @@ +package tc.oc.pgm.autojoin; + +import me.anxuiz.settings.Setting; +import me.anxuiz.settings.SettingBuilder; +import me.anxuiz.settings.types.BooleanType; + +public class AutoJoinSetting { + private static final Setting INSTANCE = new SettingBuilder() + .name("AutoJoin").alias("aj") + .summary("Automatically join a team when the match starts") + .type(new BooleanType()) + .defaultValue(true) + .get(); + + public static Setting get() { + return INSTANCE; + } +} diff --git a/PGM/src/main/java/tc/oc/pgm/picker/PickerMatchModule.java b/PGM/src/main/java/tc/oc/pgm/picker/PickerMatchModule.java index 809bdea89..628f2ff5e 100644 --- a/PGM/src/main/java/tc/oc/pgm/picker/PickerMatchModule.java +++ b/PGM/src/main/java/tc/oc/pgm/picker/PickerMatchModule.java @@ -22,7 +22,6 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; -import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.event.player.PlayerLocaleChangeEvent; @@ -40,6 +39,7 @@ import tc.oc.commons.core.chat.Component; import tc.oc.commons.core.formatting.StringUtils; import tc.oc.pgm.PGMTranslations; +import tc.oc.pgm.autojoin.AutoJoinMatchModule; import tc.oc.pgm.blitz.BlitzEvent; import tc.oc.pgm.classes.ClassMatchModule; import tc.oc.pgm.classes.ClassModule; @@ -96,15 +96,22 @@ public boolean matches(MaterialData material) { private final ComponentRenderContext renderer; private final JoinMatchModule jmm; private final BlitzMatchModule bmm; + private final AutoJoinMatchModule autoJoinMatchModule; private final boolean hasTeams; private final boolean hasClasses; private final Set picking = new HashSet<>(); - @Inject PickerMatchModule(ComponentRenderContext renderer, JoinMatchModule jmm, BlitzMatchModule bmm, Optional teamModule, Optional classModule) { + @Inject PickerMatchModule(ComponentRenderContext renderer, + JoinMatchModule jmm, + BlitzMatchModule bmm, + AutoJoinMatchModule autoJoinMatchModule, + Optional teamModule, + Optional classModule) { this.renderer = renderer; this.jmm = jmm; this.bmm = bmm; + this.autoJoinMatchModule = autoJoinMatchModule; this.hasTeams = teamModule.isPresent(); this.hasClasses = classModule.isPresent(); } @@ -288,11 +295,8 @@ public void closeMonitoredInventory(final InventoryCloseEvent event) { } @EventHandler - public void rightClickIcon(final ObserverInteractEvent event) { - if(event.getClickType() != ClickType.RIGHT) return; - + public void handleClickIcon(final ObserverInteractEvent event) { MatchPlayer player = event.getPlayer(); - if(!canUse(player)) return; ItemStack hand = event.getClickedItem(); if(ItemUtils.isNothing(hand)) return; @@ -300,17 +304,34 @@ public void rightClickIcon(final ObserverInteractEvent event) { String displayName = hand.getItemMeta().getDisplayName(); if(displayName == null) return; - if(hand.getType() == Button.JOIN.material) { - event.setCancelled(true); - if(canOpenWindow(player)) { - showWindow(player); - } else { - // If there is nothing to pick, just join immediately - jmm.requestJoin(player, JoinRequest.user()); - } - } else if(hand.getType() == Button.LEAVE.material) { - event.setCancelled(true); - jmm.requestObserve(player); + if(hand.getType() != Button.JOIN.material) return; + + switch(event.getClickType()) { + // Autojoin feature - Player left clicks the hat(cancels Autojoin) + case LEFT: + if(autoJoinMatchModule.shouldAutoJoin(player)) { + autoJoinMatchModule.cancelAutojoin(player); + } + player.sendHotbarMessage(new Component(ChatColor.DARK_PURPLE).translate("autojoin.cancelled").bold(true)); + break; + case RIGHT: + if(!canUse(player)) return; + + if(hand.getType() == Button.JOIN.material) { + event.setCancelled(true); + if(canOpenWindow(player)) { + showWindow(player); + } else { + // If there is nothing to pick, just join immediately + jmm.requestJoin(player, JoinRequest.user()); + } + // Removed until this has some use - currently does nothing + //} else if(hand.getType() == Button.LEAVE.material) { + // event.setCancelled(true); + // jmm.requestObserve(player); + // + } + break; } } diff --git a/PGM/src/main/java/tc/oc/pgm/start/StartCountdown.java b/PGM/src/main/java/tc/oc/pgm/start/StartCountdown.java index d0f09da04..9684858bb 100644 --- a/PGM/src/main/java/tc/oc/pgm/start/StartCountdown.java +++ b/PGM/src/main/java/tc/oc/pgm/start/StartCountdown.java @@ -2,6 +2,7 @@ import java.time.Duration; import javax.annotation.Nullable; +import javax.inject.Inject; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.chat.BaseComponent; @@ -10,6 +11,7 @@ import org.bukkit.entity.Player; import tc.oc.commons.core.chat.Component; import tc.oc.commons.core.util.Comparables; +import tc.oc.pgm.autojoin.AutoJoinMatchModule; import tc.oc.pgm.match.Match; import tc.oc.pgm.match.MatchState; import tc.oc.pgm.teams.Team; @@ -28,6 +30,7 @@ public class StartCountdown extends PreMatchCountdown { // or implementing some kind of countdown listener system. private final @Nullable TeamMatchModule tmm; private final StartMatchModule smm; + private final AutoJoinMatchModule autoJoinMatchModule; private final Duration huddle; private boolean autoBalanced, balanceWarningSent; protected final boolean forced; @@ -38,6 +41,7 @@ public StartCountdown(Match match, boolean forced, Duration huddle) { this.forced = forced; this.smm = match.needMatchModule(StartMatchModule.class); this.tmm = match.getMatchModule(TeamMatchModule.class); + this.autoJoinMatchModule = match.needMatchModule(AutoJoinMatchModule.class); } protected boolean willHuddle() { @@ -73,7 +77,15 @@ public void onStart(Duration remaining, Duration total) { public void onTick(Duration remaining, Duration total) { super.onTick(remaining, total); + if(remaining.getSeconds() <= 10) { + // Autojoin feature - Send the player hotbar messages and alert them that match is starting + autoJoinMatchModule.joiningPlayers() + .forEach(player -> player.sendHotbarMessage(new Component(ChatColor.DARK_PURPLE).translate("autojoin.starting", + String.valueOf(remaining.getSeconds())).bold(true))); + } + if(remaining.getSeconds() >= 1 && remaining.getSeconds() <= 3) { + autoJoinMatchModule.enterAllPlayers(); // Auto-balance runs at match start as well, but try to run it a few seconds in advance if(this.tmm != null && !this.autoBalanced) { this.autoBalanced = true;