Merge remote-tracking branch 'refs/remotes/origin/master' into develop-feedback
This commit is contained in:
commit
f0ffb3ad21
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
19
gradlew
vendored
19
gradlew
vendored
@ -55,7 +55,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
@ -83,7 +83,8 @@ done
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
@ -144,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
@ -152,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
@ -201,11 +202,11 @@ fi
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
|
20
gradlew.bat
vendored
20
gradlew.bat
vendored
@ -43,11 +43,11 @@ set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
|
@ -19,7 +19,6 @@ public final class Main extends JavaPlugin {
|
||||
private static Logger logger;
|
||||
|
||||
private List<Appliance> appliances;
|
||||
private HttpServer httpApi;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
@ -62,7 +61,7 @@ public final class Main extends JavaPlugin {
|
||||
Main.logger().info(String.format("Initialized %d appliances!", appliances.size()));
|
||||
|
||||
Main.logger().info("Starting HTTP API...");
|
||||
this.httpApi = new HttpServer();
|
||||
new HttpServer();
|
||||
|
||||
getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord");
|
||||
Main.logger().info("Startup complete!");
|
||||
@ -76,7 +75,7 @@ public final class Main extends JavaPlugin {
|
||||
appliance.onDisable();
|
||||
appliance.destruct(this);
|
||||
});
|
||||
this.httpApi.stop();
|
||||
|
||||
HandlerList.unregisterAll(this);
|
||||
Bukkit.getScheduler().cancelTasks(this);
|
||||
Main.logger().info("Disabled " + appliances.size() + " appliances!");
|
||||
|
@ -24,10 +24,6 @@ public class HttpServer {
|
||||
Main.instance().getAppliances().forEach(appliance -> appliance.httpApi(new ApiBuilder(appliance)));
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
Spark.stop();
|
||||
}
|
||||
|
||||
public record Response(Status status, Object error, Object response) {
|
||||
public enum Status {
|
||||
FAILURE,
|
||||
|
@ -0,0 +1,132 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.acInform;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.ComponentBuilder;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class AcInform extends Appliance {
|
||||
public void processCommand(@NotNull String[] args) {
|
||||
String anticheatName = null;
|
||||
String playerName = null;
|
||||
String checkName = null;
|
||||
Integer violationCount = null;
|
||||
|
||||
for(int i = 0; i < args.length; i++) {
|
||||
if(!args[i].startsWith("--")) continue;
|
||||
if(i == args.length-1) continue;
|
||||
String nextArgument = args[i+1];
|
||||
if(nextArgument.startsWith("--")) continue;
|
||||
|
||||
switch(args[i]) {
|
||||
case "--anticheatName" -> anticheatName = nextArgument;
|
||||
case "--playerName" -> playerName = nextArgument;
|
||||
case "--check" -> checkName = nextArgument;
|
||||
case "--violationCount" -> violationCount = Integer.valueOf(nextArgument);
|
||||
}
|
||||
}
|
||||
|
||||
this.notifyAdmins(anticheatName, playerName, checkName, violationCount);
|
||||
}
|
||||
|
||||
public void notifyAdmins(@Nullable String anticheatName, @Nullable String playerName, @Nullable String checkName, @Nullable Integer violationCount) {
|
||||
ComponentBuilder<TextComponent, TextComponent.Builder> component = Component.text();
|
||||
Component prefix = Component.text("# ", NamedTextColor.DARK_RED);
|
||||
NamedTextColor textColor = NamedTextColor.GRAY;
|
||||
|
||||
if(playerName == null || playerName.isBlank()) throw new ApplianceCommand.Error("acinform command needs a player (--playerName)");
|
||||
|
||||
if(anticheatName != null && !anticheatName.isBlank()) {
|
||||
component.append(
|
||||
Component.newline()
|
||||
.append(prefix)
|
||||
.append(Component.text("[", textColor))
|
||||
.append(Component.text("Anticheat", NamedTextColor.RED))
|
||||
.append(Component.text("] ", textColor))
|
||||
.append(Component.text(anticheatName, NamedTextColor.WHITE))
|
||||
.append(Component.text(":", textColor))
|
||||
);
|
||||
}
|
||||
|
||||
component.append(
|
||||
Component.newline()
|
||||
.append(prefix)
|
||||
.append(Component.text("Player ", textColor))
|
||||
.append(Component.text(playerName, NamedTextColor.WHITE))
|
||||
.append(Component.text(" "))
|
||||
);
|
||||
|
||||
if(checkName == null || checkName.isBlank()) {
|
||||
component.append(Component.text("got detected by Anticheat", textColor));
|
||||
} else if(violationCount != null){
|
||||
component.append(
|
||||
Component.text("failed ", textColor)
|
||||
.append(Component.text(String.format("%sx ", violationCount), NamedTextColor.WHITE))
|
||||
.append(Component.text("'", textColor))
|
||||
.append(Component.text(checkName, NamedTextColor.WHITE))
|
||||
.append(Component.text("'", textColor))
|
||||
);
|
||||
} else {
|
||||
component.append(
|
||||
Component.text("failed ", textColor)
|
||||
.append(Component.text("'", textColor))
|
||||
.append(Component.text(checkName, NamedTextColor.WHITE))
|
||||
.append(Component.text("'", textColor))
|
||||
);
|
||||
}
|
||||
|
||||
component.append(
|
||||
Component.newline()
|
||||
.append(prefix)
|
||||
|
||||
.append(Component.text("[", NamedTextColor.GRAY))
|
||||
.append(Component.text("Report", NamedTextColor.GOLD))
|
||||
.append(Component.text("]", NamedTextColor.GRAY))
|
||||
.clickEvent(ClickEvent.suggestCommand(String.format("/report %s anticheat %s flagged %s", playerName, anticheatName, checkName)))
|
||||
);
|
||||
|
||||
component.append(
|
||||
Component.text(" [", NamedTextColor.GRAY)
|
||||
.append(Component.text("Kick", NamedTextColor.GOLD))
|
||||
.append(Component.text("]", NamedTextColor.GRAY))
|
||||
.clickEvent(ClickEvent.suggestCommand(String.format("/kick %s", playerName)))
|
||||
);
|
||||
|
||||
component.append(
|
||||
Component.text(" [", NamedTextColor.GRAY)
|
||||
.append(Component.text("Panic Ban", NamedTextColor.GOLD))
|
||||
.append(Component.text("]", NamedTextColor.GRAY))
|
||||
.clickEvent(ClickEvent.suggestCommand(String.format("/panicban %s", playerName)))
|
||||
);
|
||||
|
||||
component.append(
|
||||
Component.text(" [", NamedTextColor.GRAY)
|
||||
.append(Component.text("Teleport", NamedTextColor.GOLD))
|
||||
.append(Component.text("]", NamedTextColor.GRAY))
|
||||
.clickEvent(ClickEvent.suggestCommand(String.format("/tp %s", playerName)))
|
||||
);
|
||||
|
||||
component.appendNewline();
|
||||
TextComponent finalMessage = component.build();
|
||||
|
||||
Bukkit.getOnlinePlayers().stream()
|
||||
.filter(player -> player.hasPermission("admin"))
|
||||
.forEach(player -> player.sendMessage(finalMessage));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<ApplianceCommand<?>> commands() {
|
||||
return List.of(
|
||||
new AcInformCommand()
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.acInform;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class AcInformCommand extends ApplianceCommand<AcInform> {
|
||||
public AcInformCommand() {
|
||||
super("acInform");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
|
||||
if(sender instanceof Player) throw new ApplianceCommand.Error("Dieser Command ist nicht für Spieler!");
|
||||
getAppliance().processCommand(args);
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.adminChat;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class AdminChat extends Appliance {
|
||||
public void sendMessage(Player sender, String message) {
|
||||
Component privatePrefix = Component
|
||||
.text("[Admin] ", NamedTextColor.LIGHT_PURPLE)
|
||||
.clickEvent(ClickEvent.suggestCommand(AdminChatCommand.commandName));
|
||||
|
||||
Bukkit.getOnlinePlayers().stream()
|
||||
.filter(player -> player.hasPermission("admin"))
|
||||
.forEach(player -> {
|
||||
Component formattedMessage = Component.text()
|
||||
.append(privatePrefix)
|
||||
.append(sender.displayName())
|
||||
.append(Component.text(" > ", NamedTextColor.DARK_GRAY))
|
||||
.append(Component.text(message))
|
||||
.build();
|
||||
player.sendMessage(formattedMessage);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<ApplianceCommand<?>> commands() {
|
||||
return List.of(new AdminChatCommand());
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.adminChat;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class AdminChatCommand extends ApplianceCommand.PlayerChecked<AdminChat> {
|
||||
public static final String commandName = "adminchat";
|
||||
|
||||
public AdminChatCommand() {
|
||||
super(commandName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
|
||||
if(!sender.hasPermission("admin")) return;
|
||||
|
||||
String message = String.join(" ", args);
|
||||
getAppliance().sendMessage(getPlayer(), message);
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.afkTag;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||
import io.papermc.paper.event.player.AsyncChatEvent;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
|
||||
public class AfkResetListener extends ApplianceListener<AfkTag> {
|
||||
@EventHandler
|
||||
public void onMove(PlayerMoveEvent event) {
|
||||
getAppliance().resetTiming(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInteract(PlayerInteractEvent event) {
|
||||
getAppliance().resetTiming(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onChat(AsyncChatEvent event) {
|
||||
getAppliance().resetTiming(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onJoin(PlayerJoinEvent event) {
|
||||
getAppliance().resetTiming(event.getPlayer());
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.afkTag;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.Main;
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.appliances.displayName.DisplayName;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
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.List;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
public class AfkTag extends Appliance implements DisplayName.DisplayNamed {
|
||||
private final WeakHashMap<Player, Long> afkTimings = new WeakHashMap<>();
|
||||
private static final int updateIntervalSeconds = 30;
|
||||
private static final int afkWhenMillis = 5 * 60 * 1000;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
Bukkit.getScheduler().runTaskTimerAsynchronously(
|
||||
Main.instance(),
|
||||
this::checkAfkPlayers,
|
||||
Ticks.TICKS_PER_SECOND,
|
||||
Ticks.TICKS_PER_SECOND * updateIntervalSeconds
|
||||
);
|
||||
}
|
||||
|
||||
public void resetTiming(Player player) {
|
||||
boolean wasAfk = isAfk(player);
|
||||
this.afkTimings.put(player, System.currentTimeMillis());
|
||||
if (wasAfk) this.updateAfkPrefix(player);
|
||||
}
|
||||
|
||||
private void checkAfkPlayers() {
|
||||
this.afkTimings.keySet().forEach((player) -> {
|
||||
if(!isAfk(player)) return;
|
||||
this.updateAfkPrefix(player);
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isAfk(Player player) {
|
||||
if(player.isSleeping()) return false;
|
||||
|
||||
long lastTimeActive = this.afkTimings.getOrDefault(player, 0L);
|
||||
long timeSinceLastActive = System.currentTimeMillis() - lastTimeActive;
|
||||
return timeSinceLastActive >= afkWhenMillis;
|
||||
}
|
||||
|
||||
private void updateAfkPrefix(Player player) {
|
||||
Main.instance().getAppliance(DisplayName.class).update(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Component getNamePrefix(Player player) {
|
||||
if(isAfk(player)) return Component.text("[ᵃᶠᵏ]", NamedTextColor.GRAY)
|
||||
.hoverEvent(HoverEvent.showText(Component.text("Der Spieler ist AFK")));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<Listener> listeners() {
|
||||
return List.of(new AfkResetListener());
|
||||
}
|
||||
}
|
@ -4,7 +4,9 @@ import eu.mhsl.craftattack.spawn.Main;
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.appliances.adminMarker.AdminMarker;
|
||||
import eu.mhsl.craftattack.spawn.appliances.adminMarker.AdminMarkerListener;
|
||||
import eu.mhsl.craftattack.spawn.appliances.afkTag.AfkTag;
|
||||
import eu.mhsl.craftattack.spawn.appliances.outlawed.Outlawed;
|
||||
import eu.mhsl.craftattack.spawn.appliances.sleepTag.SleepTag;
|
||||
import eu.mhsl.craftattack.spawn.appliances.yearRank.YearRank;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.ComponentBuilder;
|
||||
@ -13,17 +15,24 @@ import net.kyori.adventure.text.format.TextColor;
|
||||
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.function.Supplier;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class DisplayName extends Appliance {
|
||||
public interface DisplayNamed {
|
||||
@Nullable Component getNamePrefix(Player player);
|
||||
}
|
||||
|
||||
public void update(Player player) {
|
||||
TextColor playerColor = queryAppliance(AdminMarker.class).getPlayerColor(player);
|
||||
List<Supplier<Component>> prefixes = List.of(
|
||||
() -> queryAppliance(Outlawed.class).getNamePrefix(player),
|
||||
() -> queryAppliance(YearRank.class).getNamePrefix(player)
|
||||
() -> queryAppliance(YearRank.class).getNamePrefix(player),
|
||||
() -> queryAppliance(AfkTag.class).getNamePrefix(player),
|
||||
() -> queryAppliance(SleepTag.class).getNamePrefix(player)
|
||||
);
|
||||
|
||||
ComponentBuilder<TextComponent, TextComponent.Builder> playerName = Component.text();
|
||||
|
@ -0,0 +1,39 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.endPrevent;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||
import eu.mhsl.craftattack.spawn.config.Configuration;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class EndPrevent extends Appliance {
|
||||
private final String endDisabledKey = "endDisabled";
|
||||
private boolean endDisabled;
|
||||
|
||||
public EndPrevent() {
|
||||
super("endPrevent");
|
||||
this.endDisabled = localConfig().getBoolean(endDisabledKey);
|
||||
}
|
||||
|
||||
public void setEndDisabled(boolean disabled) {
|
||||
localConfig().set(endDisabledKey, disabled);
|
||||
Configuration.saveChanges();
|
||||
this.endDisabled = disabled;
|
||||
}
|
||||
|
||||
public boolean isEndDisabled() {
|
||||
return endDisabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<Listener> listeners() {
|
||||
return List.of(new PreventEnderEyeUseListener());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<ApplianceCommand<?>> commands() {
|
||||
return List.of(new EndPreventCommand());
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.endPrevent;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class EndPreventCommand extends ApplianceCommand<EndPrevent> {
|
||||
private final Map<String, Boolean> arguments = Map.of("preventEnd", true, "allowEnd", false);
|
||||
|
||||
public EndPreventCommand() {
|
||||
super("endPrevent");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
|
||||
if(args.length == 1 && arguments.containsKey(args[0])) {
|
||||
getAppliance().setEndDisabled(arguments.get(args[0]));
|
||||
sender.sendMessage(Component.text("Setting updated!", NamedTextColor.GREEN));
|
||||
}
|
||||
sender.sendMessage(Component.text(
|
||||
String.format("The End is %s!", getAppliance().isEndDisabled() ? "open" : "closed"),
|
||||
NamedTextColor.GOLD
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||
return arguments.keySet().stream().toList();
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.endPrevent;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
|
||||
public class PreventEnderEyeUseListener extends ApplianceListener<EndPrevent> {
|
||||
@EventHandler
|
||||
public void onEnderEyeInteraction(PlayerInteractEvent event) {
|
||||
if(event.getClickedBlock() == null) return;
|
||||
if(!event.getClickedBlock().getType().equals(Material.END_PORTAL_FRAME)) return;
|
||||
if(event.getItem() == null) return;
|
||||
if(!event.getItem().getType().equals(Material.ENDER_EYE)) return;
|
||||
|
||||
if(!getAppliance().isEndDisabled()) return;
|
||||
|
||||
event.setCancelled(true);
|
||||
event.getPlayer().sendActionBar(Component.text("Das End ist noch nicht freigeschaltet!", NamedTextColor.RED));
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.infoBars;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.Main;
|
||||
import net.kyori.adventure.bossbar.BossBar;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.util.Ticks;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
public abstract class Bar {
|
||||
private BossBar bossBar;
|
||||
private final BukkitTask updateTask;
|
||||
|
||||
public Bar() {
|
||||
long refreshRateInTicks = this.refresh().get(ChronoUnit.SECONDS) * Ticks.TICKS_PER_SECOND;
|
||||
this.updateTask = Bukkit.getScheduler().runTaskTimerAsynchronously(
|
||||
Main.instance(),
|
||||
this::update,
|
||||
refreshRateInTicks,
|
||||
refreshRateInTicks
|
||||
);
|
||||
}
|
||||
|
||||
public BossBar getBossBar() {
|
||||
if(this.bossBar == null) this.bossBar = this.createBar();
|
||||
return this.bossBar;
|
||||
}
|
||||
|
||||
private BossBar createBar() {
|
||||
return BossBar.bossBar(
|
||||
this.title(),
|
||||
this.correctedProgress(),
|
||||
this.color(),
|
||||
this.overlay()
|
||||
);
|
||||
}
|
||||
|
||||
private void update() {
|
||||
if(this.bossBar == null) return;
|
||||
|
||||
this.beforeRefresh();
|
||||
this.bossBar.name(this.title());
|
||||
this.bossBar.progress(this.correctedProgress());
|
||||
this.bossBar.color(this.color());
|
||||
this.bossBar.overlay(this.overlay());
|
||||
}
|
||||
|
||||
public void stopUpdate() {
|
||||
this.updateTask.cancel();
|
||||
}
|
||||
|
||||
private float correctedProgress() {
|
||||
return Math.clamp(this.progress(), 0, 1);
|
||||
}
|
||||
|
||||
protected void beforeRefresh() {}
|
||||
protected abstract Duration refresh();
|
||||
protected abstract String name();
|
||||
|
||||
protected abstract Component title();
|
||||
protected abstract float progress();
|
||||
protected abstract BossBar.Color color();
|
||||
protected abstract BossBar.Overlay overlay();
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.infoBars;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class InfoBarCommand extends ApplianceCommand.PlayerChecked<InfoBars> {
|
||||
public InfoBarCommand() {
|
||||
super("infobar");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
|
||||
if(args.length == 0) throw new Error("<show|hide|hideall> [bar name]");
|
||||
switch(args[0]) {
|
||||
case "hideAll" -> getAppliance().hideAll(getPlayer());
|
||||
case "show" -> getAppliance().show(getPlayer(), args[1]);
|
||||
case "hide" -> getAppliance().hide(getPlayer(), args[1]);
|
||||
default -> throw new Error("Erlaubte Optionen sind 'show', 'hide', 'hideAll'!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||
if(args.length == 1) return List.of("show", "hide", "hideAll");
|
||||
return getAppliance().getInfoBars().stream().map(Bar::name).toList();
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.infoBars;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.Main;
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||
import eu.mhsl.craftattack.spawn.appliances.infoBars.bars.MsptBar;
|
||||
import eu.mhsl.craftattack.spawn.appliances.infoBars.bars.PlayerCounterBar;
|
||||
import eu.mhsl.craftattack.spawn.appliances.infoBars.bars.TpsBar;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class InfoBars extends Appliance {
|
||||
private final NamespacedKey infoBarKey = new NamespacedKey(Main.instance(), "infobars");
|
||||
private final List<Bar> infoBars = List.of(
|
||||
new TpsBar(),
|
||||
new MsptBar(),
|
||||
new PlayerCounterBar()
|
||||
);
|
||||
|
||||
public void showAll(Player player) {
|
||||
this.getStoredBars(player).forEach(bar -> this.show(player, bar));
|
||||
}
|
||||
|
||||
public void hideAll(Player player) {
|
||||
this.getStoredBars(player).forEach(bar -> this.hide(player, bar));
|
||||
this.setStoredBars(player, List.of());
|
||||
}
|
||||
|
||||
public void show(Player player, String bar) {
|
||||
this.validateBarName(bar);
|
||||
List<String> existingBars = new ArrayList<>(this.getStoredBars(player));
|
||||
existingBars.add(bar);
|
||||
player.showBossBar(this.getBarByName(bar).getBossBar());
|
||||
this.setStoredBars(player, existingBars);
|
||||
}
|
||||
|
||||
public void hide(Player player, String bar) {
|
||||
this.validateBarName(bar);
|
||||
List<String> existingBars = new ArrayList<>(this.getStoredBars(player));
|
||||
existingBars.remove(bar);
|
||||
player.hideBossBar(this.getBarByName(bar).getBossBar());
|
||||
this.setStoredBars(player, existingBars);
|
||||
}
|
||||
|
||||
private List<String> getStoredBars(Player player) {
|
||||
PersistentDataContainer container = player.getPersistentDataContainer();
|
||||
if(!container.has(infoBarKey)) return List.of();
|
||||
return container.get(infoBarKey, PersistentDataType.LIST.strings());
|
||||
}
|
||||
|
||||
private void setStoredBars(Player player, List<String> bars) {
|
||||
player.getPersistentDataContainer().set(infoBarKey, PersistentDataType.LIST.strings(), bars);
|
||||
}
|
||||
|
||||
private Bar getBarByName(String name) {
|
||||
return infoBars.stream()
|
||||
.filter(bar -> bar.name().equalsIgnoreCase(name))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private void validateBarName(String name) {
|
||||
if(getBarByName(name) == null) throw new ApplianceCommand.Error(String.format("Ungültiger infobar name '%s'", name));
|
||||
}
|
||||
|
||||
public List<Bar> getInfoBars() {
|
||||
return infoBars;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
infoBars.forEach(Bar::stopUpdate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<Listener> listeners() {
|
||||
return List.of(new ShowPreviousBarsListener());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<ApplianceCommand<?>> commands() {
|
||||
return List.of(new InfoBarCommand());
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.infoBars;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
|
||||
public class ShowPreviousBarsListener extends ApplianceListener<InfoBars> {
|
||||
@EventHandler
|
||||
public void onJoin(PlayerJoinEvent event) {
|
||||
getAppliance().showAll(event.getPlayer());
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.infoBars.bars;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliances.infoBars.Bar;
|
||||
import eu.mhsl.craftattack.spawn.util.statistics.ServerMonitor;
|
||||
import eu.mhsl.craftattack.spawn.util.text.ColorUtil;
|
||||
import net.kyori.adventure.bossbar.BossBar;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
public class MsptBar extends Bar {
|
||||
@Override
|
||||
protected Duration refresh() {
|
||||
return Duration.ofSeconds(3);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String name() {
|
||||
return "mspt";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Component title() {
|
||||
return Component.text()
|
||||
.append(Component.text("M"))
|
||||
.append(Component.text("illi", NamedTextColor.GRAY))
|
||||
.append(Component.text("S"))
|
||||
.append(Component.text("econds ", NamedTextColor.GRAY))
|
||||
.append(Component.text("P"))
|
||||
.append(Component.text("er ", NamedTextColor.GRAY))
|
||||
.append(Component.text("T"))
|
||||
.append(Component.text("ick", NamedTextColor.GRAY))
|
||||
.append(Component.text(": "))
|
||||
.append(Component.text(String.format("%.2f", this.currentMSPT()), ColorUtil.msptColor(this.currentMSPT())))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float progress() {
|
||||
return this.currentMSPT() / 50f;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BossBar.Color color() {
|
||||
return BossBar.Color.BLUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BossBar.Overlay overlay() {
|
||||
return BossBar.Overlay.PROGRESS;
|
||||
}
|
||||
|
||||
private float currentMSPT() {
|
||||
return ServerMonitor.getServerMSPT();
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.infoBars.bars;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.Main;
|
||||
import eu.mhsl.craftattack.spawn.appliances.infoBars.Bar;
|
||||
import eu.mhsl.craftattack.spawn.appliances.playerlimit.PlayerLimit;
|
||||
import eu.mhsl.craftattack.spawn.util.text.ColorUtil;
|
||||
import net.kyori.adventure.bossbar.BossBar;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
public class PlayerCounterBar extends Bar {
|
||||
@Override
|
||||
protected Duration refresh() {
|
||||
return Duration.ofSeconds(3);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String name() {
|
||||
return "playerCounter";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Component title() {
|
||||
TextColor color = ColorUtil.mapGreenToRed(this.getCurrentPlayerCount(), 0, this.getMaxPlayerCount(), true);
|
||||
return Component.text()
|
||||
.append(Component.text("Spieler online: "))
|
||||
.append(Component.text(this.getCurrentPlayerCount(), color))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float progress() {
|
||||
return (float) this.getCurrentPlayerCount() / this.getMaxPlayerCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BossBar.Color color() {
|
||||
return BossBar.Color.BLUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BossBar.Overlay overlay() {
|
||||
return BossBar.Overlay.PROGRESS;
|
||||
}
|
||||
|
||||
private int getCurrentPlayerCount() {
|
||||
return Bukkit.getOnlinePlayers().size();
|
||||
}
|
||||
|
||||
private int getMaxPlayerCount() {
|
||||
return Main.instance().getAppliance(PlayerLimit.class).getLimit();
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.infoBars.bars;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliances.infoBars.Bar;
|
||||
import eu.mhsl.craftattack.spawn.util.text.ColorUtil;
|
||||
import net.kyori.adventure.bossbar.BossBar;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
public class TpsBar extends Bar {
|
||||
@Override
|
||||
protected Duration refresh() {
|
||||
return Duration.ofSeconds(3);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String name() {
|
||||
return "tps";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Component title() {
|
||||
return Component.text()
|
||||
.append(Component.text("T"))
|
||||
.append(Component.text("icks ", NamedTextColor.GRAY))
|
||||
.append(Component.text("P"))
|
||||
.append(Component.text("er ", NamedTextColor.GRAY))
|
||||
.append(Component.text("S"))
|
||||
.append(Component.text("econds", NamedTextColor.GRAY))
|
||||
.append(Component.text(": "))
|
||||
.append(Component.text(String.format("%.2f", this.currentTps()), ColorUtil.tpsColor(this.currentTps())))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float progress() {
|
||||
return this.currentTps() / 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BossBar.Color color() {
|
||||
return BossBar.Color.BLUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BossBar.Overlay overlay() {
|
||||
return BossBar.Overlay.NOTCHED_20;
|
||||
}
|
||||
|
||||
private float currentTps() {
|
||||
return (float) Bukkit.getTPS()[0];
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.maintenance;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -10,7 +12,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class MaintenanceCommand extends ApplianceCommand<Maintenance> {
|
||||
Map<String, Boolean> arguments = Map.of("enable", true, "disable", false);
|
||||
private final Map<String, Boolean> arguments = Map.of("enable", true, "disable", false);
|
||||
|
||||
public MaintenanceCommand() {
|
||||
super("maintanance");
|
||||
@ -18,9 +20,14 @@ public class MaintenanceCommand extends ApplianceCommand<Maintenance> {
|
||||
|
||||
@Override
|
||||
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
|
||||
if(args.length != 1 || !arguments.containsKey(args[0])) throw new Error("Argument 'enable' oder 'disable' gefordert!");
|
||||
getAppliance().setState(arguments.get(args[0]));
|
||||
sender.sendMessage(String.format("Maintanance: %b", getAppliance().isInMaintenance()));
|
||||
if(args.length == 1 && arguments.containsKey(args[0])) {
|
||||
getAppliance().setState(arguments.get(args[0]));
|
||||
sender.sendMessage(Component.text("Maintanance mode updated!", NamedTextColor.GREEN));
|
||||
}
|
||||
sender.sendMessage(Component.text(
|
||||
String.format("Maintanance mode is %b", getAppliance().isInMaintenance()),
|
||||
NamedTextColor.GOLD
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -12,9 +12,9 @@ public class PreventMaintenanceJoinListener extends ApplianceListener<Maintenanc
|
||||
if(event.getPlayer().hasPermission("bypassMaintainance")) return;
|
||||
|
||||
DisconnectInfo disconnectInfo = new DisconnectInfo(
|
||||
"Wartunsarbeiten",
|
||||
"Server für Spieler nicht verfügbar",
|
||||
"Zurzeit können nur Admins dem Server beitreten!",
|
||||
"Bitte warte bis die Warungsarbeiten wieder deaktiviert werden.",
|
||||
"Bitte versuche es später erneut.",
|
||||
event.getPlayer().getUniqueId()
|
||||
);
|
||||
|
||||
|
@ -17,7 +17,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Outlawed extends Appliance {
|
||||
public class Outlawed extends Appliance implements DisplayName.DisplayNamed {
|
||||
public final int timeoutInMs = 1000 * 60 * 60 * 6;
|
||||
private final Map<UUID, Long> timeouts = new HashMap<>();
|
||||
|
||||
@ -110,6 +110,7 @@ public class Outlawed extends Appliance {
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getNamePrefix(Player player) {
|
||||
if(isOutlawed(player)) {
|
||||
return Component.text("[☠]", NamedTextColor.RED)
|
||||
|
@ -0,0 +1,32 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.playtime;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||
import eu.mhsl.craftattack.spawn.util.text.DataSizeConverter;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.util.Ticks;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.Statistic;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Playtime extends Appliance {
|
||||
public Component getFormattedPlaytime(OfflinePlayer player) {
|
||||
int playtimeInTicks = player.getStatistic(Statistic.PLAY_ONE_MINUTE);
|
||||
String playtime = DataSizeConverter.formatSecondsToHumanReadable(playtimeInTicks / Ticks.TICKS_PER_SECOND);
|
||||
return Component.text()
|
||||
.append(Component.text("Der Spieler ", NamedTextColor.GRAY))
|
||||
.append(Component.text(Objects.requireNonNull(player.getName())))
|
||||
.append(Component.text(" hat eine Spielzeit von ", NamedTextColor.GRAY))
|
||||
.append(Component.text(playtime, NamedTextColor.GOLD))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<ApplianceCommand<?>> commands() {
|
||||
return List.of(new PlaytimeCommand());
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.playtime;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.Main;
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class PlaytimeCommand extends ApplianceCommand.PlayerChecked<Playtime> {
|
||||
public PlaytimeCommand() {
|
||||
super("playtime");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
|
||||
String playerName = args.length == 1 ? args[0] : getPlayer().getName();
|
||||
|
||||
Bukkit.getScheduler().runTaskAsynchronously(Main.instance(), () -> {
|
||||
OfflinePlayer player = Bukkit.getOfflinePlayer(playerName);
|
||||
if (!player.hasPlayedBefore()) {
|
||||
sender.sendMessage(Component.text("Der Spieler existiert nicht!", NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
sender.sendMessage(getAppliance().getFormattedPlaytime(player));
|
||||
});
|
||||
}
|
||||
}
|
@ -11,16 +11,17 @@ import org.bukkit.event.entity.FoodLevelChangeEvent;
|
||||
public class PlayerInvincibleListener extends ApplianceListener<ProjectStart> {
|
||||
@EventHandler
|
||||
public void onDamage(EntityDamageEvent event) {
|
||||
if(event.getEntity() instanceof Player) event.setCancelled(getAppliance().isEnabled());
|
||||
if(!(event.getEntity() instanceof Player)) return;
|
||||
if(getAppliance().isEnabled()) event.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onHunger(FoodLevelChangeEvent event) {
|
||||
event.setCancelled(getAppliance().isEnabled());
|
||||
if(getAppliance().isEnabled()) event.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onHit(PrePlayerAttackEntityEvent event) {
|
||||
event.setCancelled(getAppliance().isEnabled());
|
||||
if(getAppliance().isEnabled()) event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.sleepTag;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.player.PlayerBedEnterEvent;
|
||||
import org.bukkit.event.player.PlayerBedLeaveEvent;
|
||||
|
||||
public class SleepStateChangeListener extends ApplianceListener<SleepTag> {
|
||||
@EventHandler
|
||||
public void onBedEnter(PlayerBedEnterEvent event) {
|
||||
if(!event.getBedEnterResult().equals(PlayerBedEnterEvent.BedEnterResult.OK)) return;
|
||||
getAppliance().updateSleeping(event.getPlayer(), true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onBedLeave(PlayerBedLeaveEvent event) {
|
||||
getAppliance().updateSleeping(event.getPlayer(), false);
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.sleepTag;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.Main;
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.appliances.displayName.DisplayName;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
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.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class SleepTag extends Appliance implements DisplayName.DisplayNamed {
|
||||
private final Set<Player> sleepingPlayers = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
Bukkit.getScheduler().runTaskTimerAsynchronously(
|
||||
Main.instance(),
|
||||
this::cleanup,
|
||||
Ticks.TICKS_PER_SECOND * 60,
|
||||
Ticks.TICKS_PER_SECOND * 60
|
||||
);
|
||||
}
|
||||
|
||||
public void updateSleeping(Player player, boolean isSleeping) {
|
||||
if(isSleeping) {
|
||||
this.sleepingPlayers.add(player);
|
||||
} else {
|
||||
this.sleepingPlayers.remove(player);
|
||||
}
|
||||
this.updateDisplayName(player);
|
||||
}
|
||||
|
||||
private void updateDisplayName(Player player) {
|
||||
Main.instance().getAppliance(DisplayName.class).update(player);
|
||||
}
|
||||
|
||||
private void cleanup() {
|
||||
List<Player> invalidEntries = this.sleepingPlayers.stream()
|
||||
.filter(player -> !player.isConnected())
|
||||
.filter(player -> !player.isSleeping())
|
||||
.toList();
|
||||
|
||||
invalidEntries.forEach(this.sleepingPlayers::remove);
|
||||
invalidEntries.forEach(this::updateDisplayName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Component getNamePrefix(Player player) {
|
||||
if(this.sleepingPlayers.contains(player))
|
||||
return Component.text("[\uD83D\uDCA4]", NamedTextColor.GRAY)
|
||||
.hoverEvent(HoverEvent.showText(Component.text("Der Spieler liegt in einem Bett")));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<Listener> listeners() {
|
||||
return List.of(new SleepStateChangeListener());
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ package eu.mhsl.craftattack.spawn.appliances.yearRank;
|
||||
import eu.mhsl.craftattack.spawn.Main;
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||
import eu.mhsl.craftattack.spawn.appliances.displayName.DisplayName;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
@ -15,7 +16,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
public class YearRank extends Appliance {
|
||||
public class YearRank extends Appliance implements DisplayName.DisplayNamed {
|
||||
record CraftAttackYear(String name) {}
|
||||
private final Map<UUID, List<CraftAttackYear>> rankMap = new HashMap<>();
|
||||
|
||||
@ -44,6 +45,7 @@ public class YearRank extends Appliance {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Component getNamePrefix(Player player) {
|
||||
if(!rankMap.containsKey(player.getUniqueId())) return null;
|
||||
int yearCount = rankMap.get(player.getUniqueId()).size();
|
||||
|
@ -0,0 +1,12 @@
|
||||
package eu.mhsl.craftattack.spawn.util.statistics;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ServerMonitor {
|
||||
public static float getServerMSPT() {
|
||||
long[] times = Bukkit.getServer().getTickTimes();
|
||||
return ((float) Arrays.stream(times).sum() / times.length) * 1.0E-6f;
|
||||
}
|
||||
}
|
@ -15,4 +15,13 @@ public class ColorUtil {
|
||||
|
||||
return TextColor.color(Color.getHSBColor(hue / 360, 1f, 1f).getRGB());
|
||||
}
|
||||
|
||||
public static TextColor msptColor(float mspt) {
|
||||
if(mspt > 50) return TextColor.color(255, 0, 0);
|
||||
return ColorUtil.mapGreenToRed(mspt, 25, 60, true);
|
||||
}
|
||||
|
||||
public static TextColor tpsColor(float tps) {
|
||||
return ColorUtil.mapGreenToRed(tps, 15, 20, false);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package eu.mhsl.craftattack.spawn.util.text;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.util.statistics.NetworkMonitor;
|
||||
import eu.mhsl.craftattack.spawn.util.statistics.ServerMonitor;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.ComponentBuilder;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
@ -12,7 +13,6 @@ import org.bukkit.entity.Player;
|
||||
import java.awt.*;
|
||||
import java.lang.management.OperatingSystemMXBean;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@ -55,15 +55,12 @@ public class ComponentUtil {
|
||||
}
|
||||
|
||||
public static Component getFormattedTickTimes(boolean detailed) {
|
||||
long[] times = Bukkit.getServer().getTickTimes();
|
||||
float mspt = ((float) Arrays.stream(times).sum() / times.length) * 1.0E-6f;
|
||||
float mspt = ServerMonitor.getServerMSPT();
|
||||
float roundedMspt = Math.round(mspt * 100f) / 100f;
|
||||
int loadPercentage = (int) (Math.min(100, (mspt / 50.0) * 100));
|
||||
float roundedTPS = Math.round(Bukkit.getTPS()[0] * 100f) / 100f;
|
||||
|
||||
TextColor msptColor = ColorUtil.mapGreenToRed(roundedMspt, 0, 50, true);
|
||||
TextColor percentageColor = ColorUtil.mapGreenToRed(loadPercentage, 80, 100, true);
|
||||
TextColor tpsColor = ColorUtil.mapGreenToRed(roundedTPS, 15, 20, false);
|
||||
|
||||
ComponentBuilder<TextComponent, TextComponent.Builder> tickTimes = Component.text()
|
||||
.append(Component.text("Serverlast: ", NamedTextColor.GRAY))
|
||||
@ -72,12 +69,12 @@ public class ComponentUtil {
|
||||
|
||||
if(detailed) {
|
||||
tickTimes
|
||||
.append(Component.text(roundedMspt + "mspt", msptColor))
|
||||
.append(Component.text(roundedMspt + "mspt", ColorUtil.msptColor(mspt)))
|
||||
.append(Component.text(" | ", NamedTextColor.GRAY));
|
||||
}
|
||||
|
||||
return tickTimes
|
||||
.append(Component.text(roundedTPS + "tps", tpsColor))
|
||||
.append(Component.text(roundedTPS + "tps", ColorUtil.tpsColor(roundedTPS)))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -38,4 +38,18 @@ public class DataSizeConverter {
|
||||
hours %= 60;
|
||||
return String.format("%dd%dh%dm%ds", days, hours, minutes, seconds);
|
||||
}
|
||||
|
||||
public static String formatSecondsToHumanReadable(int seconds) {
|
||||
if (seconds < 0) return "unsupported";
|
||||
|
||||
int minutes = seconds / 60;
|
||||
int hours = minutes / 60;
|
||||
int days = hours / 24;
|
||||
|
||||
seconds %= 60;
|
||||
minutes %= 60;
|
||||
hours %= 60;
|
||||
|
||||
return String.format("%dd %dh %dm %ds", days, hours, minutes, seconds);
|
||||
}
|
||||
}
|
@ -66,4 +66,7 @@ packselect:
|
||||
author: "Pack Author(s)"
|
||||
url: "https://example.com/download/pack.zip"
|
||||
hash: "" # SHA1 hash of ZIP file (will be auto determined by the server on startup when not set)
|
||||
icon: "" # base64 player-head texture, can be obtained from sites like https://minecraft-heads.com/ under developers > Value
|
||||
icon: "" # base64 player-head texture, can be obtained from sites like https://minecraft-heads.com/ under developers > Value
|
||||
|
||||
endPrevent:
|
||||
endDisabled: true
|
@ -41,4 +41,10 @@ commands:
|
||||
maintanance:
|
||||
yearRank:
|
||||
msg:
|
||||
r:
|
||||
r:
|
||||
playtime:
|
||||
adminchat:
|
||||
aliases: [ "sc" ]
|
||||
acInform:
|
||||
infobar:
|
||||
endPrevent:
|
||||
|
Loading…
x
Reference in New Issue
Block a user