diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java b/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java
index e22f5bd..0e66d6d 100644
--- a/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java
+++ b/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java
@@ -98,6 +98,7 @@ public class FightSystem extends JavaPlugin {
new ClickAnalyzer();
new BlockPlaceCollision();
new HotbarKit.HotbarKitListener();
+ new JoinRequestListener();
new OneShotStateDependent(ArenaMode.All, FightState.PreSchemSetup, () -> Fight.playSound(SWSound.BLOCK_NOTE_PLING.getSound(), 100.0f, 2.0f));
new EnterHandler();
@@ -136,12 +137,10 @@ public class FightSystem extends JavaPlugin {
new LeaveCommand();
new KitCommand();
new RemoveCommand();
- new AcceptCommand();
+ new RequestsCommand();
new WGCommand();
new TBCommand();
- new DeclineCommand();
new GamemodeCommand();
- new InviteCommand();
new ReadyCommand();
new AkCommand();
new LeaderCommand();
diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.properties b/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.properties
index 7a0114a..a6ab2ab 100644
--- a/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.properties
+++ b/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.properties
@@ -25,13 +25,6 @@ FIGHT_ALREADY_STARTED=§cThe fight already started
NOT_LEADER=§cYou aren't a leader
PLAYER_UNAVAILABLE=§cThe player is not in an arena
-NO_INVITATION=§cYou weren't invited by any team
-INVITATION_DECLINED=§cInvitation declined
-INVITATION_DECLINED_TEAM=§e{0} §chas declined the invitation
-PLAYER_IN_TEAM=§e{0} §cis already in a team
-ALREADY_INVITED=§e{0} §cwas invited
-INVITATION_SENT=§e{0} §7invited
-
NOT_IN_TEAM=§e{0} §cis not in your team
KIT_UNAVAILABLE=§cThis kit does not exist
@@ -41,8 +34,6 @@ GAMEMODE_NOT_ALLOWED=§cChanging gamemode is not permitted
GAMEMODE_UNKNOWN=§cUnknown gamemode {0}
GAMEMODE_HELP=§8/§7gm §8[§egamemode§8]
-INVITE_HELP=§8/§einvite §8[§eplayer§8]
-
LEADER_FULL=§cAll teams already have a leader
ALREADY_IN_TEAM=§cYou are already in a team
@@ -58,12 +49,6 @@ WIN_HELP=§8/§7win §8[§eteam §8or §etie§8]
# GUI
-INVITATION_TITLE=Invitation from {0}
-INVITATION_ACCEPT=§aAccept
-INVITATION_DECLINE=§cDecline
-INVITATION_CHAT_ACCEPT=§8/§aaccept§8, §7to §aaccept§7 the invitation
-INVITATION_CHAT_DECLINE=§8/§cdecline§8, §7to §cdecline§7 the invitation
-
STATE_TITLE=Fight state
STATE_PRE_LEADER_SETUP=§7Team leader waiting phase
STATE_PRE_SCHEM_SETUP=§7Schematic selection phase
@@ -73,8 +58,6 @@ STATE_RUNNING=§eFighting phase
STATE_SPECTATE_WIN=§7Victory {0}
STATE_SPECTATE_TIE=§7Draw
-INVITE_TITLE=Invite player
-
REMOVE_TITLE=Kick player
KIT_SELECTION_TITLE=Kit selection
@@ -119,7 +102,6 @@ SKIP_NOT_READY=§c§mSkipping to next event
TEAM_CHAT={0}{1}§8» {0}{2}
CHOOSE_KIT=§eChoose kit
RESPAWN=§eRespawn
-INVITE_PLAYERS=§eInvite player
REMOVE_PLAYERS=§cKick player
CHOOSE_SCHEMATIC=§eChoose {0}
SCHEMATIC_REQUIRED=§cChoose a schematic first
@@ -244,3 +226,22 @@ WIN_CREWMATE_DEAD={0} §7killed all team mates
AMONG_US_IMPOSTER_MESSAGE = §4You are the Imposter§8! §7Kill all your team mates to win the game!
AMONG_US_IMPOSTER_AMONG_MESSAGE = §4There is an Imposter among us§8! §7Kill him to win the game!
+
+
+# Invites
+JOIN_REQUEST=§7Request join
+JOIN_REQUEST_TITLE=Request join
+JOIN_REQUEST_ALREADY=§cYou have already sent a join request
+JOIN_REQUEST_TEAM=§7Join {0}
+JOIN_REQUEST_CONFIRMATION=§7Join request submitted
+JOIN_REQUEST_NOTIFICATION=§e{0} §7requests joining team {1}§8. §7Accept or decline using §8/§erequests
+
+REQUESTS=§7Open join requests
+REQUESTS_TITLE=Open join requests
+REQUEST_DECLINED=§cJoin of {0} declined
+REQUEST_YOUR_DECLINED=§cYour join request was declined
+REQUESTS_LEFT_CLICK=§eLeft click §7to §eaccept§8!
+REQUESTS_RIGHT_CLICK=§eRight click §7to §edecline§8!
+
+NO_JOIN_REQUEST=§cThe player did not request joining
+NO_CONFIRMATION=§cNo confirmation necessary
\ No newline at end of file
diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem_de.properties b/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem_de.properties
index fff7bc4..415652c 100644
--- a/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem_de.properties
+++ b/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem_de.properties
@@ -23,13 +23,6 @@ FIGHT_ALREADY_STARTED=§cDer Kampf hat bereits begonnen
NOT_LEADER=§cDu bist kein Leader
PLAYER_UNAVAILABLE=§cDer Spieler ist nicht in der Arena
-NO_INVITATION=§cDu wurdest von keinem Team eingeladen
-INVITATION_DECLINED=§cEinladung abgelehnt
-INVITATION_DECLINED_TEAM=§e{0} §chat die Einladung abgelehnt
-PLAYER_IN_TEAM=§e{0} §cist bereits in einem Team
-ALREADY_INVITED=§e{0} §cwurde bereits eingeladen
-INVITATION_SENT=§e{0} §7eingeladen
-
NOT_IN_TEAM=§e{0} §cist nicht in deinem Team
KIT_UNAVAILABLE=§cDieses Kit gibt es nicht
@@ -39,8 +32,6 @@ GAMEMODE_NOT_ALLOWED=§cSpielmodusänderung verboten
GAMEMODE_UNKNOWN=§cUnbekannter Spielmodus {0}
GAMEMODE_HELP=§8/§7gm §8[§eSpielmodus§8]
-INVITE_HELP=§8/§einvite §8[§eSpieler§8]
-
LEADER_FULL=§cAlle Teams haben bereits einen Leader
ALREADY_IN_TEAM=§cDu bist bereits in einem Team
@@ -56,12 +47,6 @@ WIN_HELP=§8/§7win §8[§eTeam §8oder §etie§8]
# GUI
-INVITATION_TITLE=Einladung von {0}
-INVITATION_ACCEPT=§aAnnehmen
-INVITATION_DECLINE=§cAblehnen
-INVITATION_CHAT_ACCEPT=§8/§aaccept§8, §7um die Einladung §aanzunehmen
-INVITATION_CHAT_DECLINE=§8/§cdecline§8, §7um die Einladung §cabzulehnen
-
STATE_TITLE=Kampfstatus
STATE_PRE_LEADER_SETUP=§7Teamleaderwartephase
STATE_PRE_SCHEM_SETUP=§7Schemauswahlphase
@@ -71,8 +56,6 @@ STATE_RUNNING=§eKampfphase
STATE_SPECTATE_WIN=§7Sieg {0}
STATE_SPECTATE_TIE=§7Unentschieden
-INVITE_TITLE=Spieler einladen
-
REMOVE_TITLE=Spieler rauswerfen
KIT_SELECTION_TITLE=Kitauswahl
@@ -116,7 +99,6 @@ SKIP_READY=§aBeschleunigung zum nächsten Event
SKIP_NOT_READY=§c§mBeschleunigung zum nächsten Event
CHOOSE_KIT=§eKit wählen
RESPAWN=§eRespawn
-INVITE_PLAYERS=§eSpieler einladen
REMOVE_PLAYERS=§cSpieler rauswerfen
CHOOSE_SCHEMATIC=§e{0} wählen
SCHEMATIC_REQUIRED=§cZuerst muss eine Schematic gewählt sein
@@ -228,4 +210,22 @@ WIN_IMPOSTER_DEAD={0} §7 hat den Imposter getötet
WIN_CREWMATE_DEAD={0} §7 hat alle Kameraden getötet
AMONG_US_IMPOSTER_MESSAGE = §4Du bist ein Imposter§8! §7Du musst alle Kameraden töten, um zu gewinnen.
-AMONG_US_IMPOSTER_AMONG_MESSAGE = §4Es ist ein Imposter unter uns§8! §7Tötet ihn, um das Spiel zu gewinnen!
\ No newline at end of file
+AMONG_US_IMPOSTER_AMONG_MESSAGE = §4Es ist ein Imposter unter uns§8! §7Tötet ihn, um das Spiel zu gewinnen!
+
+# Invites
+JOIN_REQUEST=§7Teambeitritt anfragen
+JOIN_REQUEST_TITLE=Teambeitritt anfragen
+JOIN_REQUEST_ALREADY=§cDu hast bereits ein Team um Beitritt angefragt
+JOIN_REQUEST_TEAM={0} §7beitreten
+JOIN_REQUEST_CONFIRMATION=§7Teambeitritt angefragt
+JOIN_REQUEST_NOTIFICATION=§e{0} §7möchte Team {1} §7beitreten§8. §7Akzeptiere oder lehne ab mit §8/§erequests
+
+REQUESTS=§7Offene Beitrittsanfragen
+REQUESTS_TITLE=Offene Beitrittsanfragen
+REQUEST_DECLINED=§cBeitritt von {0} abgelehnt
+REQUEST_YOUR_DECLINED=§cDeine Betrittsanfrage wurde abgelehnt
+REQUESTS_LEFT_CLICK=§eLinksklick §7um §eanzunehmen§8!
+REQUESTS_RIGHT_CLICK=§eRechtsklick §7um §eabzulehnen§8!
+
+NO_JOIN_REQUEST=§cDer Spieler hat noch keinen Beitritt angefragt
+NO_CONFIRMATION=§cKeine Zustimmung nötig
diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/commands/AcceptCommand.java b/FightSystem_Core/src/de/steamwar/fightsystem/commands/AcceptCommand.java
deleted file mode 100644
index 0e23db4..0000000
--- a/FightSystem_Core/src/de/steamwar/fightsystem/commands/AcceptCommand.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- This file is a part of the SteamWar software.
-
- Copyright (C) 2020 SteamWar.de-Serverteam
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
-*/
-
-package de.steamwar.fightsystem.commands;
-
-import de.steamwar.fightsystem.ArenaMode;
-import de.steamwar.fightsystem.states.FightState;
-import de.steamwar.fightsystem.states.StateDependentCommand;
-import org.bukkit.command.Command;
-import org.bukkit.command.CommandExecutor;
-import org.bukkit.command.CommandSender;
-import org.bukkit.entity.Player;
-
-public class AcceptCommand implements CommandExecutor {
-
- public AcceptCommand() {
- new StateDependentCommand(ArenaMode.VariableTeams, FightState.Setup, "accept", this);
- }
-
- @Override
- public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
- if(!(sender instanceof Player)) {
- return false;
- }
- Player player = (Player) sender;
-
- Commands.acceptInvitation(player);
- return false;
- }
-}
diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/commands/Commands.java b/FightSystem_Core/src/de/steamwar/fightsystem/commands/Commands.java
index 5ff08b0..6102728 100644
--- a/FightSystem_Core/src/de/steamwar/fightsystem/commands/Commands.java
+++ b/FightSystem_Core/src/de/steamwar/fightsystem/commands/Commands.java
@@ -47,14 +47,6 @@ public class Commands {
return false;
}
- private static FightTeam checkGetInvitedTeam(Player p){
- FightTeam fightTeam = Fight.getInvitedTeam(p);
- if(fightTeam == null){
- FightSystem.getMessage().sendPrefixless("NO_INVITATION", p, ChatMessageType.ACTION_BAR);
- }
- return fightTeam;
- }
-
private static FightPlayer checkGetPlayer(Player p){
FightPlayer fightPlayer = Fight.getFightPlayer(p);
if(fightPlayer == null){
@@ -104,30 +96,6 @@ public class Commands {
fightTeam.skip();
}
- static void acceptInvitation(Player p){
- if(checkSetup(p))
- return;
-
- FightTeam team = checkGetInvitedTeam(p);
- if(team == null)
- return;
-
- team.addMember(p);
- }
-
- static void declineInvitation(Player p){
- if(checkSetup(p))
- return;
-
- FightTeam team = checkGetInvitedTeam(p);
- if(team == null)
- return;
-
- FightSystem.getMessage().sendPrefixless("INVITATION_DECLINED", p, ChatMessageType.ACTION_BAR);
- team.broadcast("INVITATION_DECLINED_TEAM", p.getName());
- team.getInvited().remove(p);
- }
-
static void leaveTeam(Player p){
if(checkSetup(p))
return;
@@ -139,37 +107,6 @@ public class Commands {
fightTeam.removePlayer(p);
}
- static void invite(Player p, String invited){
- if(checkSetup(p))
- return;
-
- FightTeam fightTeam = checkGetTeam(p);
- if(fightTeam == null)
- return;
-
- FightPlayer fightPlayer = checkGetLeader(p);
- if(fightPlayer == null)
- return;
-
- Player target = checkGetPlayer(p, invited);
- if(target == null)
- return;
-
- if(Fight.getPlayerTeam(target) != null) {
- FightSystem.getMessage().sendPrefixless("PLAYER_IN_TEAM", p, ChatMessageType.ACTION_BAR, target.getName());
- return;
- }
-
- if(Fight.getOpposite(fightTeam).getInvited().contains(target) || fightTeam.getInvited().contains(target)) {
- FightSystem.getMessage().sendPrefixless("ALREADY_INVITED", p, ChatMessageType.ACTION_BAR, target.getName());
- return;
- }
-
- FightSystem.getMessage().sendPrefixless("INVITATION_SENT", p, ChatMessageType.ACTION_BAR, target.getName());
- fightTeam.getInvited().add(target);
- GUI.invitation(p, target);
- }
-
static void kick(Player p, String kicked){
if(checkSetup(p))
return;
diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/commands/DeclineCommand.java b/FightSystem_Core/src/de/steamwar/fightsystem/commands/DeclineCommand.java
deleted file mode 100644
index 3fa9906..0000000
--- a/FightSystem_Core/src/de/steamwar/fightsystem/commands/DeclineCommand.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- This file is a part of the SteamWar software.
-
- Copyright (C) 2020 SteamWar.de-Serverteam
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
-*/
-
-package de.steamwar.fightsystem.commands;
-
-import de.steamwar.fightsystem.ArenaMode;
-import de.steamwar.fightsystem.states.FightState;
-import de.steamwar.fightsystem.states.StateDependentCommand;
-import org.bukkit.command.Command;
-import org.bukkit.command.CommandExecutor;
-import org.bukkit.command.CommandSender;
-import org.bukkit.entity.Player;
-
-public class DeclineCommand implements CommandExecutor {
-
- public DeclineCommand() {
- new StateDependentCommand(ArenaMode.VariableTeams, FightState.Setup, "decline", this);
- }
-
- @Override
- public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
- if(!(sender instanceof Player)) {
- return false;
- }
- Player player = (Player) sender;
-
- Commands.declineInvitation(player);
- return false;
- }
-}
diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/commands/GUI.java b/FightSystem_Core/src/de/steamwar/fightsystem/commands/GUI.java
index 5b04b80..cb63550 100644
--- a/FightSystem_Core/src/de/steamwar/fightsystem/commands/GUI.java
+++ b/FightSystem_Core/src/de/steamwar/fightsystem/commands/GUI.java
@@ -21,12 +21,10 @@ package de.steamwar.fightsystem.commands;
import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.FightSystem;
-import de.steamwar.fightsystem.fight.Fight;
-import de.steamwar.fightsystem.fight.FightPlayer;
-import de.steamwar.fightsystem.fight.FightTeam;
-import de.steamwar.fightsystem.fight.Kit;
+import de.steamwar.fightsystem.fight.*;
import de.steamwar.fightsystem.listener.PersonalKitCreator;
import de.steamwar.fightsystem.states.FightState;
+import de.steamwar.fightsystem.utils.ColorConverter;
import de.steamwar.inventory.*;
import de.steamwar.message.Message;
import de.steamwar.sql.PersonalKit;
@@ -47,23 +45,27 @@ public class GUI {
private static final Message msg = FightSystem.getMessage();
- static void invitation(Player p, Player target){
- SWInventory inv = new SWInventory(target, 9, msg.parse("INVITATION_TITLE", target, p.getName()));
- inv.setItem(0, SWItem.getDye(10), (byte)10, msg.parse("INVITATION_ACCEPT", target), (ClickType click) ->{
- Commands.acceptInvitation(target);
- target.closeInventory();
+ @SuppressWarnings("deprecation")
+ private static void addTeamRequest(Player p, SWInventory inv, int pos, FightTeam team) {
+ byte colorCode = ColorConverter.chat2dye(team.getColor()).getDyeData();
+ inv.setItem(pos, SWItem.getDye(colorCode), colorCode, msg.parse("JOIN_REQUEST_TEAM", p, team.getColoredName()), click -> {
+ p.closeInventory();
+ new JoinRequest(p, team);
});
- inv.setItem(8, SWItem.getDye(1), (byte)1, msg.parse("INVITATION_DECLINE", target), (ClickType click) ->{
- Commands.declineInvitation(target);
- target.closeInventory();
- });
- inv.addCloseCallback((ClickType click) ->{
- if(Fight.getInvitedTeam(target) != null){
- msg.sendPrefixless("INVITATION_CHAT_ACCEPT", target);
- msg.sendPrefixless("INVITATION_CHAT_DECLINE", target);
- }
- });
- inv.setCallback(-999, (ClickType click) -> target.closeInventory());
+ }
+
+ public static void joinRequest(Player p) {
+ if(JoinRequest.get(p) != null) {
+ msg.sendPrefixless("JOIN_REQUEST_ALREADY", p, ChatMessageType.ACTION_BAR);
+ return;
+ }
+
+ SWInventory inv = new SWInventory(p, 9, msg.parse("JOIN_REQUEST_TITLE", p));
+ FightTeam team = Fight.getPlayerTeam(p);
+ if(team != Fight.getRedTeam())
+ addTeamRequest(p, inv, team == null ? 0 : 4, Fight.getBlueTeam());
+ if(team != Fight.getBlueTeam())
+ addTeamRequest(p, inv, team == null ? 8 : 4, Fight.getRedTeam());
inv.open();
}
@@ -84,12 +86,11 @@ public class GUI {
inv.open();
}
- public static void chooseInvitation(Player p){
- List> players = SWListInv.createPlayerList(p.getUniqueId());
- players.removeIf(swItemUUIDPair -> Fight.getFightPlayer(Bukkit.getPlayer(swItemUUIDPair.getObject())) != null);
- SWListInv inv = new SWListInv<>(p, msg.parse("INVITE_TITLE", p), players, (ClickType click, UUID player) -> {
- Commands.invite(p, SteamwarUser.get(player).getUserName());
+ public static void chooseJoinRequests(Player p){
+ List> players = JoinRequest.openRequests(p, Fight.getPlayerTeam(p));
+ SWListInv inv = new SWListInv<>(p, msg.parse("REQUESTS_TITLE", p), players, (ClickType click, Player player) -> {
p.closeInventory();
+ RequestsCommand.onJoinRequest(p, player, click.isLeftClick() ? JoinRequest::accept : JoinRequest::decline);
});
inv.setCallback(-999, (ClickType click) -> p.closeInventory());
inv.open();
diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/commands/InviteCommand.java b/FightSystem_Core/src/de/steamwar/fightsystem/commands/RequestsCommand.java
similarity index 53%
rename from FightSystem_Core/src/de/steamwar/fightsystem/commands/InviteCommand.java
rename to FightSystem_Core/src/de/steamwar/fightsystem/commands/RequestsCommand.java
index 67cf6b1..36c2a1e 100644
--- a/FightSystem_Core/src/de/steamwar/fightsystem/commands/InviteCommand.java
+++ b/FightSystem_Core/src/de/steamwar/fightsystem/commands/RequestsCommand.java
@@ -21,6 +21,10 @@ package de.steamwar.fightsystem.commands;
import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.FightSystem;
+import de.steamwar.fightsystem.fight.Fight;
+import de.steamwar.fightsystem.fight.FightPlayer;
+import de.steamwar.fightsystem.fight.FightTeam;
+import de.steamwar.fightsystem.fight.JoinRequest;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentCommand;
import org.bukkit.command.Command;
@@ -28,25 +32,46 @@ import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
-public class InviteCommand implements CommandExecutor {
+import java.util.function.BiConsumer;
- public InviteCommand() {
- new StateDependentCommand(ArenaMode.VariableTeams, FightState.Setup, "invite", this);
+public class RequestsCommand implements CommandExecutor {
+
+ public RequestsCommand() {
+ new StateDependentCommand(ArenaMode.VariableTeams, FightState.AntiSpectate, "request", this);
+ new StateDependentCommand(ArenaMode.VariableTeams, FightState.AntiSpectate, "requests", this);
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
- if(!(sender instanceof Player)) {
+ if(!(sender instanceof Player))
return false;
- }
Player player = (Player) sender;
-
- if(args.length != 1){
- FightSystem.getMessage().sendPrefixless("INVITE_HELP", player);
+ FightPlayer fp = Fight.getFightPlayer(player);
+ if(fp == null || !(fp.isLeader() || fp.isLiving())) {
+ GUI.joinRequest(player);
return false;
}
- Commands.invite(player, args[0]);
+ if(Commands.checkGetLeader(player) == null)
+ return false;
+
+ GUI.chooseJoinRequests(player);
return false;
}
+
+ public static void onJoinRequest(Player player, Player target, BiConsumer handleJoinRequest) {
+ JoinRequest request = JoinRequest.get(target);
+ if(request == null) {
+ FightSystem.getMessage().send("NO_JOIN_REQUEST", player);
+ return;
+ }
+
+ FightTeam team = Fight.getPlayerTeam(player);
+ if(!request.required(team)) {
+ FightSystem.getMessage().send("NO_CONFIRMATION", player);
+ return;
+ }
+
+ handleJoinRequest.accept(request, team);
+ }
}
diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/countdown/EnternCountdown.java b/FightSystem_Core/src/de/steamwar/fightsystem/countdown/EnternCountdown.java
index c27fc2b..c5c19b5 100644
--- a/FightSystem_Core/src/de/steamwar/fightsystem/countdown/EnternCountdown.java
+++ b/FightSystem_Core/src/de/steamwar/fightsystem/countdown/EnternCountdown.java
@@ -25,17 +25,32 @@ import de.steamwar.fightsystem.fight.FightPlayer;
import de.steamwar.fightsystem.utils.Message;
import de.steamwar.fightsystem.utils.SWSound;
import de.steamwar.techhider.ProtocolUtils;
+import de.steamwar.fightsystem.winconditions.Wincondition;
import net.md_5.bungee.api.ChatMessageType;
import java.util.List;
public class EnternCountdown extends Countdown {
+ private static int calcTime(FightPlayer fp) {
+ int time = Config.EnterStages.get(fp.getKit().getEnterStage());
+
+ Countdown countdown = Wincondition.getTimeOverCountdown();
+ if(countdown != null) {
+ time -= Config.TimeoutTime - countdown.getTimeLeft();
+
+ if(time < 0)
+ time = 0;
+ }
+
+ return time;
+ }
+
private final FightPlayer fightPlayer;
private List chunkPos;
public EnternCountdown(FightPlayer fp) {
- super(Config.EnterStages.get(fp.getKit().getEnterStage()), new Message("ENTERN_COUNTDOWN"), SWSound.BLOCK_NOTE_PLING, false);
+ super(calcTime(fp), new Message("ENTERN_COUNTDOWN"), SWSound.BLOCK_NOTE_PLING, false);
fightPlayer = fp;
enable();
}
diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/fight/Fight.java b/FightSystem_Core/src/de/steamwar/fightsystem/fight/Fight.java
index 750941e..6f465e8 100644
--- a/FightSystem_Core/src/de/steamwar/fightsystem/fight/Fight.java
+++ b/FightSystem_Core/src/de/steamwar/fightsystem/fight/Fight.java
@@ -62,14 +62,6 @@ public class Fight {
throw new IllegalArgumentException();
}
- public static FightTeam getInvitedTeam(Player player){
- if(redTeam.getInvited().contains(player))
- return redTeam;
- else if(blueTeam.getInvited().contains(player))
- return blueTeam;
- return null;
- }
-
public static FightPlayer getFightPlayer(Player player) {
if(redTeam.isPlayerInTeam(player))
return redTeam.getFightPlayer(player);
diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightPlayer.java b/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightPlayer.java
index 5f3651a..ed2e6d5 100644
--- a/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightPlayer.java
+++ b/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightPlayer.java
@@ -23,11 +23,15 @@ import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.countdown.EnternCountdown;
import de.steamwar.sql.PersonalKit;
import de.steamwar.sql.SteamwarUser;
+import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
+import java.util.UUID;
+
public class FightPlayer {
- private final Player player;
+ private final UUID uuid;
+ private Player player;
private final FightTeam team;
private boolean isOut;
private Kit kit;
@@ -35,6 +39,7 @@ public class FightPlayer {
private EnternCountdown enternCountdown = null;
FightPlayer(Player player, FightTeam team) {
+ this.uuid = player.getUniqueId();
this.player = player;
this.team = team;
this.isOut = false;
@@ -48,13 +53,18 @@ public class FightPlayer {
kills = 0;
}
+ public void revive() {
+ isOut = false;
+ }
+
public void setOut() {
isOut = true;
stopEnternCountdown();
}
- public void setEnternCountdown(EnternCountdown countdown){
- enternCountdown = countdown;
+ public void startEnternCountdown() {
+ if(Config.EnterStages.size() > kit.getEnterStage() && kit.getEnterStage() >= 0)
+ enternCountdown = new EnternCountdown(this);
}
public void stopEnternCountdown(){
@@ -65,7 +75,10 @@ public class FightPlayer {
}
public Player getPlayer() {
- return this.player;
+ Player bukkit = Bukkit.getPlayer(uuid);
+ if(bukkit != null)
+ player = bukkit;
+ return player;
}
public boolean isLiving() {
diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java b/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java
index 70036c7..ca19f3b 100644
--- a/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java
+++ b/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java
@@ -46,6 +46,7 @@ import org.bukkit.scoreboard.NameTagVisibility;
import org.bukkit.scoreboard.Team;
import java.util.*;
+import java.util.function.Consumer;
public class FightTeam {
@@ -67,7 +68,7 @@ public class FightTeam {
setKitButton(notReadyKit, true);
if(!ArenaMode.RankedEvent.contains(Config.mode)){
- notReadyKit.setItem(2, "INVITE_PLAYERS", new ItemBuilder(Material.PAPER).removeAllAttributes().build(), GUI::chooseInvitation);
+ notReadyKit.setItem(2, "REQUESTS", new ItemBuilder(Material.PAPER).removeAllAttributes().build(), GUI::chooseJoinRequests);
notReadyKit.setItem(3, "REMOVE_PLAYERS", new ItemBuilder(SWItem.getMaterial("FIREWORK_CHARGE")).removeAllAttributes().build(), GUI::chooseRemove);
}
@@ -90,8 +91,7 @@ public class FightTeam {
private FightPlayer leader;
private int schemRank;
- private final Map players = new HashMap<>();
- private final Set invited = new HashSet<>();
+ private final Map players = new HashMap<>();
private String name;
private String prefix;
@@ -165,11 +165,11 @@ public class FightTeam {
}
public void teleportToSpawn(){
- players.forEach((player, fp) -> player.teleport(spawn));
+ players.forEach((player, fp) -> Objects.requireNonNull(Bukkit.getPlayer(player)).teleport(spawn));
}
public FightPlayer getFightPlayer(Player player) {
- return players.get(player);
+ return players.get(player.getUniqueId());
}
public boolean allPlayersOut() {
@@ -181,7 +181,7 @@ public class FightTeam {
}
public boolean isPlayerInTeam(Player player) {
- return players.containsKey(player);
+ return players.containsKey(player.getUniqueId());
}
public boolean canPlayerEntern(Player player) {
@@ -199,24 +199,24 @@ public class FightTeam {
skip = false;
ready = false;
schematic.reset();
- invited.clear();
- Set playerSet = new HashSet<>(players.keySet());
- for(Player player : playerSet){
- if(!Bukkit.getOnlinePlayers().contains(player))
+ Set playerSet = new HashSet<>(players.keySet());
+ for(UUID uuid : playerSet){
+ Player player = Bukkit.getPlayer(uuid);
+ if(player == null)
removePlayer(player);
}
FightPlayer leaderBackup = leader;
- playerSet.removeIf(player -> !Bukkit.getOnlinePlayers().contains(player));
+ playerSet.removeIf(uuid -> Bukkit.getPlayer(uuid) == null);
players.clear();
leader = null;
if(leaderBackup != null){
- playerSet.remove(leaderBackup.getPlayer());
+ playerSet.remove(leaderBackup.getPlayer().getUniqueId());
addMember(leaderBackup.getPlayer(), true);
}
- playerSet.forEach(p -> addMember(p, true));
+ playerSet.forEach(uuid -> addMember(Bukkit.getPlayer(uuid), true));
if(ArenaMode.VariableTeams.contains(Config.mode) && isLeaderless()){
List onlinePlayers = new ArrayList<>(Bukkit.getOnlinePlayers());
@@ -231,36 +231,52 @@ public class FightTeam {
}
public void broadcast(String message, Object... params) {
- players.forEach((player, fp) -> FightSystem.getMessage().sendPrefixless(message, player, ChatMessageType.ACTION_BAR, params));
+ broadcast(player -> FightSystem.getMessage().sendPrefixless(message, player, ChatMessageType.ACTION_BAR, params));
}
public void broadcastSystem(String message, Object... params) {
- players.forEach((player, fp) -> FightSystem.getMessage().send(message, player, params));
+ broadcast(player -> FightSystem.getMessage().send(message, player, params));
}
public void broadcastChat(Player sender, String message) {
- players.forEach((player, fp) -> FightSystem.getMessage().sendPrefixless("TEAM_CHAT", player, ChatMessageType.CHAT, prefix, sender.getName(), message));
+ broadcast(player -> FightSystem.getMessage().sendPrefixless("TEAM_CHAT", player, ChatMessageType.CHAT, prefix, sender.getName(), message));
+ }
+
+ private void broadcast(Consumer f) {
+ players.forEach((uuid, fightPlayer) -> {
+ Player player = Bukkit.getPlayer(uuid);
+ if(player != null)
+ f.accept(player);
+ });
}
public void addMember(Player player) {
addMember(player, false);
}
- public void addMember(Player player, boolean silent) {
+ private void addMember(Player player, boolean silent) {
final List chunksToReload = FightSystem.getTechHider().prepareChunkReload(player, false);
- FightPlayer fightPlayer = new FightPlayer(player, this);
- players.put(player, fightPlayer);
- invited.remove(player);
+ FightPlayer fightPlayer = getFightPlayer(player) != null ? getFightPlayer(player) : new FightPlayer(player, this);
+ fightPlayer.revive();
+ players.put(player.getUniqueId(), fightPlayer);
Permanent.getSpectatorTeam().removeEntry(player.getName());
team.addEntry(player.getName());
- Fight.setPlayerGamemode(player, GameMode.SURVIVAL);
player.setHealth(20);
player.setFoodLevel(20);
player.getInventory().clear();
BountifulWrapper.impl.setAttackSpeed(player);
player.teleport(spawn);
- memberKit.loadToPlayer(player);
+
+ if(FightState.Spectate.contains(FightState.getFightState())) {
+ Fight.setPlayerGamemode(player, GameMode.SPECTATOR);
+ } else {
+ Fight.setPlayerGamemode(player, GameMode.SURVIVAL);
+ (FightState.ingame() ? fightPlayer.getKit() : memberKit).loadToPlayer(player);
+ }
+ if(FightState.Running.contains(FightState.getFightState()))
+ fightPlayer.startEnternCountdown();
+
GlobalRecorder.getInstance().playerJoins(player);
FightSystem.getTechHider().reloadChunks(player, chunksToReload, false);
@@ -275,7 +291,7 @@ public class FightTeam {
PersonalKitCreator.closeIfInKitCreator(player);
List chunksToReload = FightSystem.getTechHider().prepareChunkReload(player, true);
- players.remove(player);
+ players.remove(player.getUniqueId());
team.removeEntry(player.getName());
Permanent.getSpectatorTeam().addEntry(player.getName());
@@ -291,6 +307,9 @@ public class FightTeam {
if(player.isOnline()){
FightSystem.getTechHider().reloadChunks(player, chunksToReload, true);
+
+ if(ArenaMode.VariableTeams.contains(Config.mode))
+ HotbarKit.SPECTATOR_KIT.loadToPlayer(player);
}
}
@@ -419,10 +438,6 @@ public class FightTeam {
}
}
- public Set getInvited() {
- return invited;
- }
-
public String getName() {
return name;
}
diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/fight/HotbarKit.java b/FightSystem_Core/src/de/steamwar/fightsystem/fight/HotbarKit.java
index ef2e3a3..8310d2c 100644
--- a/FightSystem_Core/src/de/steamwar/fightsystem/fight/HotbarKit.java
+++ b/FightSystem_Core/src/de/steamwar/fightsystem/fight/HotbarKit.java
@@ -23,10 +23,13 @@ import de.steamwar.core.Core;
import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.FightSystem;
+import de.steamwar.fightsystem.commands.GUI;
import de.steamwar.fightsystem.listener.PersonalKitCreator;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.fightsystem.states.StateDependentTask;
+import de.steamwar.fightsystem.utils.ItemBuilder;
+import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@@ -45,6 +48,12 @@ import java.util.function.Consumer;
public class HotbarKit extends Kit {
+ public static final HotbarKit SPECTATOR_KIT = new HotbarKit();
+ static {
+ for(int i = 0; i < 9; i++)
+ SPECTATOR_KIT.setItem(i, "JOIN_REQUEST", new ItemBuilder(Material.PAPER).removeAllAttributes().build(), GUI::joinRequest);
+ }
+
private static final int HOTBAR_SIZE = 9;
private final String[] nameTags;
@@ -87,8 +96,8 @@ public class HotbarKit extends Kit {
private static final Set clicked = new HashSet<>();
public HotbarKitListener() {
- new StateDependentListener(ArenaMode.AntiReplay, FightState.Setup, this);
- new StateDependentTask(ArenaMode.AntiReplay, FightState.Setup, clicked::clear, 10, 10);
+ new StateDependentListener(ArenaMode.AntiReplay, FightState.All, this);
+ new StateDependentTask(ArenaMode.AntiReplay, FightState.All, clicked::clear, 10, 10);
}
@EventHandler
diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/fight/JoinRequest.java b/FightSystem_Core/src/de/steamwar/fightsystem/fight/JoinRequest.java
new file mode 100644
index 0000000..13ab67a
--- /dev/null
+++ b/FightSystem_Core/src/de/steamwar/fightsystem/fight/JoinRequest.java
@@ -0,0 +1,104 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2022 SteamWar.de-Serverteam
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+
+package de.steamwar.fightsystem.fight;
+
+import de.steamwar.fightsystem.FightSystem;
+import de.steamwar.fightsystem.states.FightState;
+import de.steamwar.inventory.SWItem;
+import de.steamwar.inventory.SWListInv;
+import net.md_5.bungee.api.ChatMessageType;
+import net.md_5.bungee.api.chat.ClickEvent;
+import org.bukkit.entity.Player;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class JoinRequest {
+
+ private static final Map activeRequests = new HashMap<>();
+
+ public static List> openRequests(Player p, FightTeam team) {
+ return activeRequests.values().stream().filter(
+ request -> request.waitOnApproval.contains(team)
+ ).map(request -> {
+ SWItem item = SWItem.getPlayerSkull(request.player);
+ item.setLore(Arrays.asList(
+ FightSystem.getMessage().parse("REQUESTS_LEFT_CLICK", p),
+ FightSystem.getMessage().parse("REQUESTS_RIGHT_CLICK", p)
+ ));
+ return new SWListInv.SWListEntry<>(item, request.player);
+ }).collect(Collectors.toList());
+ }
+
+ public static void clearRequests() {
+ activeRequests.clear();
+ }
+
+ public static JoinRequest get(Player player) {
+ return activeRequests.get(player);
+ }
+
+ private final Player player;
+ private final FightTeam team;
+ private final Set waitOnApproval;
+
+ public JoinRequest(Player player, FightTeam team) {
+ this.player = player;
+ this.team = team;
+ this.waitOnApproval = new HashSet<>(FightState.ingame() ? Fight.teams() : Collections.singleton(team));
+ for(FightTeam t : waitOnApproval) {
+ FightPlayer leader = t.getLeader();
+ if(leader == null)
+ continue;
+
+ Player leaderPlayer = leader.getPlayer();
+ if(leaderPlayer == null)
+ continue;
+
+ FightSystem.getMessage().sendPrefixless("JOIN_REQUEST_NOTIFICATION", leaderPlayer, "REQUESTS", new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/requests"), player.getName(), team.getColoredName());
+ }
+
+ activeRequests.put(player, this);
+ FightSystem.getMessage().sendPrefixless("JOIN_REQUEST_CONFIRMATION", player, ChatMessageType.ACTION_BAR);
+ }
+
+ public boolean required(FightTeam decider) {
+ return waitOnApproval.contains(decider);
+ }
+
+ public void accept(FightTeam acceptor) {
+ waitOnApproval.remove(acceptor);
+
+ if(waitOnApproval.isEmpty()) {
+ team.addMember(player);
+ activeRequests.remove(player);
+ }
+ }
+
+ public void decline(FightTeam declinor) {
+ FightSystem.getMessage().sendPrefixless("REQUEST_YOUR_DECLINED", player, ChatMessageType.ACTION_BAR);
+ waitOnApproval.forEach(t -> t.broadcast("REQUEST_DECLINED", player.getName()));
+ silentDecline();
+ }
+
+ public void silentDecline() {
+ activeRequests.remove(player);
+ }
+}
diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/listener/JoinRequestListener.java b/FightSystem_Core/src/de/steamwar/fightsystem/listener/JoinRequestListener.java
new file mode 100644
index 0000000..1ed3fe8
--- /dev/null
+++ b/FightSystem_Core/src/de/steamwar/fightsystem/listener/JoinRequestListener.java
@@ -0,0 +1,74 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2022 SteamWar.de-Serverteam
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+
+package de.steamwar.fightsystem.listener;
+
+import de.steamwar.fightsystem.ArenaMode;
+import de.steamwar.fightsystem.Config;
+import de.steamwar.fightsystem.FightSystem;
+import de.steamwar.fightsystem.fight.Fight;
+import de.steamwar.fightsystem.fight.FightPlayer;
+import de.steamwar.fightsystem.fight.HotbarKit;
+import de.steamwar.fightsystem.fight.JoinRequest;
+import de.steamwar.fightsystem.states.FightState;
+import de.steamwar.fightsystem.states.OneShotStateDependent;
+import de.steamwar.fightsystem.states.StateDependentListener;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.bukkit.event.player.PlayerRespawnEvent;
+
+public class JoinRequestListener implements Listener {
+
+ public JoinRequestListener() {
+ new OneShotStateDependent(ArenaMode.VariableTeams, FightState.PreLeaderSetup, () -> Bukkit.getScheduler().runTask(FightSystem.getPlugin(), JoinRequest::clearRequests));
+ new OneShotStateDependent(ArenaMode.VariableTeams, FightState.PreRunning, () -> Bukkit.getScheduler().runTask(FightSystem.getPlugin(), JoinRequest::clearRequests));
+
+ new StateDependentListener(ArenaMode.VariableTeams, FightState.All, this);
+ }
+
+ @EventHandler(priority = EventPriority.HIGH)
+ public void onJoin(PlayerJoinEvent event) {
+ Player player = event.getPlayer();
+ FightPlayer fp = Fight.getFightPlayer(player);
+
+ if (!Config.ArenaLeaveable && (fp == null || !fp.isLiving())) {
+ HotbarKit.SPECTATOR_KIT.loadToPlayer(player);
+ }
+ }
+
+ @EventHandler
+ public void handlePlayerRespawn(PlayerRespawnEvent event) {
+ Player player = event.getPlayer();
+ if(Fight.fighting(player)) {
+ HotbarKit.SPECTATOR_KIT.loadToPlayer(player);
+ }
+ }
+
+ @EventHandler
+ public void onLeave(PlayerQuitEvent event) {
+ JoinRequest request = JoinRequest.get(event.getPlayer());
+ if(request != null)
+ request.silentDecline();
+ }
+}
diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/listener/Permanent.java b/FightSystem_Core/src/de/steamwar/fightsystem/listener/Permanent.java
index 4ae1875..b5cb0e7 100644
--- a/FightSystem_Core/src/de/steamwar/fightsystem/listener/Permanent.java
+++ b/FightSystem_Core/src/de/steamwar/fightsystem/listener/Permanent.java
@@ -93,11 +93,15 @@ public class Permanent implements Listener {
event.setJoinMessage(null);
Player player = event.getPlayer();
+ FightPlayer fp = Fight.getFightPlayer(player);
- if (!Config.ArenaLeaveable && !Fight.fighting(player)) {
+ if (!Config.ArenaLeaveable && fp == null) {
Fight.setPlayerGamemode(player, GameMode.SPECTATOR);
spectatorTeam.addEntry(player.getName());
player.teleport(Config.SpecSpawn);
+ } else if(fp != null && !fp.isLiving()) {
+ Fight.setPlayerGamemode(player, GameMode.SPECTATOR);
+ player.teleport(fp.getTeam().getSpawn());
}
}
diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/utils/EnterHandler.java b/FightSystem_Core/src/de/steamwar/fightsystem/utils/EnterHandler.java
index cec63a4..ee5aa79 100644
--- a/FightSystem_Core/src/de/steamwar/fightsystem/utils/EnterHandler.java
+++ b/FightSystem_Core/src/de/steamwar/fightsystem/utils/EnterHandler.java
@@ -19,8 +19,6 @@
package de.steamwar.fightsystem.utils;
-import de.steamwar.fightsystem.Config;
-import de.steamwar.fightsystem.countdown.EnternCountdown;
import de.steamwar.fightsystem.fight.Fight;
import de.steamwar.fightsystem.fight.FightPlayer;
import de.steamwar.fightsystem.fight.FightTeam;
@@ -53,8 +51,7 @@ public class EnterHandler implements IStateDependent {
private void registerTeam(FightTeam team){
for(FightPlayer fp : team.getPlayers()){
- if(Config.EnterStages.size() > fp.getKit().getEnterStage() && fp.getKit().getEnterStage() >= 0)
- fp.setEnternCountdown(new EnternCountdown(fp));
+ fp.startEnternCountdown();
}
}
diff --git a/FightSystem_Core/src/plugin.yml b/FightSystem_Core/src/plugin.yml
index a740a86..abc32f9 100644
--- a/FightSystem_Core/src/plugin.yml
+++ b/FightSystem_Core/src/plugin.yml
@@ -12,10 +12,9 @@ api-version: "1.13"
commands:
ak:
- accept:
- decline:
+ request:
+ requests:
leave:
- invite:
ready:
kit:
remove: