various changes for team management

This commit is contained in:
2025-05-30 12:44:48 +02:00
parent 50147a06e2
commit 8093a4a644
189 changed files with 649 additions and 358 deletions

View File

@ -1,6 +1,6 @@
package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.forbiddenItems;
import eu.mhsl.craftattack.core.appliance.ApplianceListener;
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
import net.kyori.adventure.text.Component;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntitySpawnEvent;

View File

@ -1,6 +1,6 @@
package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.forbiddenItems;
import eu.mhsl.craftattack.core.appliance.Appliance;
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Villager;

View File

@ -1,6 +1,6 @@
package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.forbiddenItems;
import eu.mhsl.craftattack.core.appliance.ApplianceListener;
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
import net.kyori.adventure.text.Component;
import org.bukkit.Material;
import org.bukkit.entity.Entity;

View File

@ -1,6 +1,6 @@
package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.forbiddenItems;
import eu.mhsl.craftattack.core.appliance.ApplianceListener;
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;

View File

@ -1,7 +1,8 @@
package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.joinProtection;
import eu.mhsl.craftattack.core.Main;
import eu.mhsl.craftattack.core.appliance.Appliance;
import eu.mhsl.craftattack.spawn.core.Main;
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
import eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.teams.Teams;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.util.Ticks;
@ -17,7 +18,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
public class JoinProtection extends Appliance {
private static final int resistanceDuration = 10;
public static final int resistanceDuration = 10;
static final class Options {
public boolean wasOnGround = false;
@ -43,11 +44,11 @@ public class JoinProtection extends Appliance {
}
public void cancelEvent(Player player, Cancellable event) {
if(!this.protectedPlayers.containsKey(player.getUniqueId())) return;
var teamCountdown = Main.instance().getAppliance(Teams.class).getTeamJoinCountdown(player);
if(teamCountdown.isFree(resistanceDuration)) return;
event.setCancelled(true);
Options option = this.protectedPlayers.get(player.getUniqueId());
int secondsLeft = Math.abs((int) ((System.currentTimeMillis() - option.joinTime) / 1000) - resistanceDuration);
int secondsLeft = Math.abs((int) ((System.currentTimeMillis() - teamCountdown.timestampSince()) / 1000) - resistanceDuration);
player.sendActionBar(
Component.text(
String.format("Du bist in %d Sekunden angreifbar", secondsLeft),

View File

@ -1,6 +1,6 @@
package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.joinProtection;
import eu.mhsl.craftattack.core.appliance.ApplianceListener;
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;

View File

@ -1,6 +1,6 @@
package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.netherPrevent;
import eu.mhsl.craftattack.core.appliance.Appliance;
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
import org.bukkit.event.Listener;
import org.jetbrains.annotations.NotNull;

View File

@ -1,6 +1,6 @@
package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.netherPrevent;
import eu.mhsl.craftattack.core.appliance.ApplianceListener;
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
import org.bukkit.event.EventHandler;
import org.bukkit.event.world.PortalCreateEvent;

View File

@ -1,9 +1,9 @@
package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.shrinkingBorder;
import eu.mhsl.craftattack.core.Main;
import eu.mhsl.craftattack.core.appliance.Appliance;
import eu.mhsl.craftattack.core.appliance.ApplianceCommand;
import eu.mhsl.craftattack.core.config.Configuration;
import eu.mhsl.craftattack.spawn.core.Main;
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand;
import eu.mhsl.craftattack.spawn.core.config.Configuration;
import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings;
import org.bukkit.Bukkit;
import org.bukkit.World;

View File

@ -1,6 +1,6 @@
package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.shrinkingBorder;
import eu.mhsl.craftattack.core.appliance.ApplianceCommand;
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;

View File

@ -1,6 +1,6 @@
package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.shrinkingBorder;
import eu.mhsl.craftattack.core.appliance.ApplianceListener;
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.TextColor;

View File

@ -0,0 +1,32 @@
package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.teams;
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
import eu.mhsl.craftattack.spawn.core.util.text.DisconnectInfo;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
class ConnectivityChangeListener extends ApplianceListener<Teams> {
@EventHandler
public void onLogin(AsyncPlayerPreLoginEvent event) {
boolean result = this.getAppliance().canLogin(event.getUniqueId());
event.kickMessage(new DisconnectInfo(
"Kein Teilnehmer",
"Du bist nicht als Teilnehmer registriert oder bist ausgeschieden!",
"Sollte dies ein Fehler sein, kontaktiere bitte einen Admin.",
event.getUniqueId()
).getComponent());
if(!result) event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER);
}
@EventHandler
public void onJoin(PlayerJoinEvent event) {
this.getAppliance().enforceTeamJoin(event.getPlayer());
}
@EventHandler
public void onLeave(PlayerQuitEvent event) {
this.getAppliance().enforceTeamLeave(event.getPlayer());
}
}

View File

@ -0,0 +1,112 @@
package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.teams;
import eu.mhsl.craftattack.spawn.core.Main;
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
import eu.mhsl.craftattack.spawn.core.util.text.DisconnectInfo;
import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.displayName.DisplayName;
import eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.joinProtection.JoinProtection;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.util.Ticks;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
public class Teams extends Appliance implements DisplayName.Prefixed, DisplayName.Colored {
private Set<VaroTeam> teams = new HashSet<>() {{
this.add(new VaroTeam(
new HashSet<>() {{
this.add(new VaroTeam.Member(UUID.fromString("3a0a699c-7f0c-319b-839c-ccc8cac8ae63"), false));
this.add(new VaroTeam.Member(UUID.fromString("959ed433-14ea-38fe-918b-75b7d09466af"), true));
}},
"Die Admins",
"#0E0E0E"
));
}};
public void refreshTeamList() {
}
public boolean canLogin(UUID playerId) {
return this.teams.stream()
.anyMatch(varoTeam -> varoTeam.hasMember(playerId) && !Objects.requireNonNull(varoTeam.getMemberById(playerId)).isDead);
}
VaroTeam getTeamFromPlayer(UUID playerId) {
return this.teams.stream()
.filter(varoTeam -> varoTeam.hasMember(playerId))
.findFirst()
.orElseThrow();
}
public void enforceTeamJoin(Player joinedPlayer) {
this.getTeamFromPlayer(joinedPlayer.getUniqueId()).joinCountdown = new VaroTeam.JoinCountdown();
DisconnectInfo disconnectInfo = new DisconnectInfo(
"Teampartner nicht beigetreten",
"Deine Verbindung wurde getrennt, da dein Teampartner keine Verbindung zum Server hergestellt hat!",
"Bitte sorge dafür, dass alle anderen Teammitglieder eine einwandfreie Internetverbindung haben und melde dich im Zweifel bei einem Admin!",
joinedPlayer.getUniqueId()
);
VaroTeam team = this.getTeamFromPlayer(joinedPlayer.getUniqueId());
Bukkit.getScheduler().scheduleSyncDelayedTask(
Main.instance(),
() -> {
team.members.stream()
.filter(member -> !member.isDead)
.filter(member -> {
Player p = Bukkit.getPlayer(member.player.getUniqueId());
return p == null || !p.isOnline();
})
.findAny()
.ifPresent(member -> team.kickTeam(disconnectInfo));
},
Ticks.TICKS_PER_SECOND * (JoinProtection.resistanceDuration / 2)
);
}
public void enforceTeamLeave(Player leftPlayer) {
DisconnectInfo disconnectInfo = new DisconnectInfo(
"Dein Teampartner hat den Server vorzeitig verlassen",
"Dein Team erhält daher einen Strike!",
"Bitte bleibt stets die vollen 30 Minuten auf dem Server!",
leftPlayer.getUniqueId()
);
VaroTeam team = this.getTeamFromPlayer(leftPlayer.getUniqueId());
Bukkit.getScheduler().scheduleSyncDelayedTask(
Main.instance(),
() -> team.kickTeam(disconnectInfo),
Ticks.TICKS_PER_SECOND
);
}
public VaroTeam.JoinCountdown getTeamJoinCountdown(Player player) {
return this.getTeamFromPlayer(player.getUniqueId()).joinCountdown;
}
@Override
public @Nullable TextColor getNameColor(Player player) {
return NamedTextColor.WHITE ;
}
@Override
public @Nullable Component getNamePrefix(Player player) {
VaroTeam team = this.getTeamFromPlayer(player.getUniqueId());
return Component.text(
String.format("[%s]", team.name),
TextColor.fromCSSHexString(team.color)
);
}
@Override
protected @NotNull List<Listener> listeners() {
return List.of(new ConnectivityChangeListener());
}
}

View File

@ -0,0 +1,78 @@
package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.teams;
import eu.mhsl.craftattack.spawn.core.util.text.DisconnectInfo;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
class VaroTeam {
public static class Member {
public final OfflinePlayer player;
public boolean isDead;
public Member(UUID playerId, boolean isDead) {
this.player = Bukkit.getOfflinePlayer(playerId);
this.isDead = isDead;
}
}
public record JoinCountdown(long timestampSince) {
public JoinCountdown() {
this(System.currentTimeMillis());
}
public boolean isFree(int countdownSeconds) {
return this.timestampSince < System.currentTimeMillis() - (countdownSeconds * 1000);
}
}
public final Set<Member> members;
public final UUID teamUuid;
public final String name;
public final String color;
public JoinCountdown joinCountdown;
public VaroTeam(Set<Member> members, String name, String color) {
this.teamUuid = UUID.randomUUID();
this.members = members;
this.name = name;
this.color = color;
}
public boolean isTeamDead() {
return this.members.stream().allMatch(member -> member.isDead);
}
public boolean hasMember(UUID uuid) {
return this.members.stream()
.anyMatch(member -> member.player.getUniqueId().equals(uuid));
}
public @Nullable Member getMemberById(UUID uuid) {
return this.members.stream()
.filter(member -> member.player.getUniqueId().equals(uuid))
.findFirst()
.orElse(null);
}
public void kickTeam() {
this.kickTeam(new DisconnectInfo(
"Unbekannter Fehler",
"Verbindung wurde aufgrund eines unbekannten Grundes getrennt",
"Falls du denkst, dass dies ein Fehler ist, melde dich bei einem Admin!",
this.teamUuid
));
}
public void kickTeam(DisconnectInfo disconnectInfo) {
this.members.stream()
.map(member -> Bukkit.getPlayer(member.player.getUniqueId()))
.filter(Objects::nonNull)
.forEach(player -> player.kick(disconnectInfo.getComponent()));
}
}

View File

@ -0,0 +1,24 @@
package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.varoDeath;
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
import eu.mhsl.craftattack.spawn.core.util.IteratorUtil;
import net.kyori.adventure.sound.Sound;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.PlayerDeathEvent;
class PlayerDeathListener extends ApplianceListener<VaroDeath> {
@EventHandler
public void onDeath(PlayerDeathEvent event) {
event.setKeepInventory(false);
this.getAppliance().registerPlayerDeath(event.getPlayer(), event.deathMessage());
Sound sound = Sound.sound(builder -> {
builder.pitch(1f);
builder.volume(1f);
builder.source(Sound.Source.MASTER);
builder.type(org.bukkit.Sound.ENTITY_LIGHTNING_BOLT_THUNDER);
});
IteratorUtil.onlinePlayers(player -> player.playSound(sound));
}
}

View File

@ -0,0 +1,39 @@
package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.varoDeath;
import eu.mhsl.craftattack.spawn.core.Main;
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
import eu.mhsl.craftattack.spawn.core.util.text.DisconnectInfo;
import eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.teams.Teams;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Objects;
public class VaroDeath extends Appliance {
public void registerPlayerDeath(Player player, @Nullable Component component) {
String deathMessage = PlainTextComponentSerializer.plainText().serialize(Objects.requireNonNull(component));
DisconnectInfo disconnectInfo = new DisconnectInfo(
deathMessage,
"Du bist gestorben, und bist daher aus dem Projekt ausgeschieden!",
"Vielen Dank für deine Teilnahme",
player.getUniqueId()
);
//TODO send player death to backend
disconnectInfo.applyKick(player);
Main.instance().getAppliance(Teams.class).refreshTeamList();
}
@Override
protected @NotNull List<Listener> listeners() {
return List.of(
new PlayerDeathListener()
);
}
}