Compare commits
	
		
			105 Commits
		
	
	
		
			859733e3dd
			...
			develop-ba
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 91a28b4500 | |||
| e745ff4721 | |||
| 23af3ff784 | |||
| bc5c9a2a13 | |||
| c220479052 | |||
| 78f87d97f0 | |||
| db13a9f0a2 | |||
| 09abfefe33 | |||
| bd3546abc8 | |||
| 8a7a0453ce | |||
| 64d0d817c0 | |||
| 713561bf07 | |||
| 4be3e528b1 | |||
| 53fca580f3 | |||
| 20fb4bf9fb | |||
| c42d259909 | |||
| 5c82c8d6da | |||
| 5910847172 | |||
| 7c254707c1 | |||
| 9ee5f6e419 | |||
| e49c3b1987 | |||
| 5ca4c70a41 | |||
| 040cae6cd1 | |||
| 324defc4a8 | |||
| dc0003b91e | |||
| d4a3c798f8 | |||
| c88c2ab6aa | |||
| 32a20cd4c5 | |||
| d7cc141b94 | |||
| 16d7347fd0 | |||
| fdf3b5c73f | |||
| 74f17e1b6d | |||
| 0d18b81399 | |||
| 1fa5fdfeb7 | |||
| 3bec5f4cbd | |||
| d38871eac9 | |||
| 238df2feff | |||
| e752d7f73b | |||
| b0df982be3 | |||
| dc1b5957f6 | |||
| 4068eae5bb | |||
| b1e3e99cb8 | |||
| b3787983d5 | |||
| 43ef28499b | |||
| 6e1ef4fd7c | |||
| ec2d243b7b | |||
| ef6f34c2b2 | |||
| 977f4ff4ec | |||
| 337727b0f0 | |||
| 44dae51e1c | |||
| 035864631d | |||
| f3b884058e | |||
| 03d4f4e6d8 | |||
| 7422a89d98 | |||
| 3590a5d278 | |||
| 15ac47b314 | |||
| af644a71ee | |||
| 0ce69f207f | |||
| 76297bb3af | |||
| 1aad8f07c4 | |||
| f26f4ed56a | |||
| 831eacaf47 | |||
| c71a2567bd | |||
| 72e88ce491 | |||
| 66d84f4677 | |||
| 427aed9a7e | |||
| 0d1e6070ce | |||
| 220fb9e229 | |||
| 9acac488f2 | |||
| d71c0d768e | |||
| 9ef4c2e96b | |||
| 5d33d2aff7 | |||
| 3f1065fd3a | |||
| aa868deeca | |||
| b6c298cec3 | |||
| 8f5a96dc31 | |||
| 2824c1053b | |||
| ccf383cdb5 | |||
| fce9449b7e | |||
| 69e971f618 | |||
| b1f188dece | |||
| a4289d5ac9 | |||
| 1fef363c50 | |||
| 558e6f84f1 | |||
| bdbb8b5824 | |||
| 8093a4a644 | |||
| 50147a06e2 | |||
| a52476650e | |||
| 0e5e841527 | |||
| ea5279dd82 | |||
| 32cbbe6c51 | |||
| 9544c953a2 | |||
| 34df173940 | |||
| ca99e6cfef | |||
| b0414ae6ab | |||
| c28d34ab88 | |||
| 9bae26044a | |||
| d1b5d81fa7 | |||
| e37e410542 | |||
| 956d2717d8 | |||
| ef7232e687 | |||
| ff31215295 | |||
| a4a254ebbe | |||
| 71d9faa9f4 | |||
| 092d33beb3 | 
| @@ -1,6 +1,8 @@ | |||||||
| dependencies { | dependencies { | ||||||
|     implementation project(':core') |     implementation project(':core') | ||||||
|  |  | ||||||
|     compileOnly 'io.papermc.paper:paper-api:1.21.1-R0.1-SNAPSHOT' |     compileOnly 'io.papermc.paper:paper-api:1.21.8-R0.1-SNAPSHOT' | ||||||
|     compileOnly 'org.geysermc.floodgate:api:2.2.2-SNAPSHOT' |     compileOnly 'org.geysermc.floodgate:api:2.2.4-SNAPSHOT' | ||||||
|  |     implementation 'org.apache.httpcomponents:httpclient:4.5.14' | ||||||
|  |     implementation 'com.sparkjava:spark-core:2.9.4' | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,14 +1,15 @@ | |||||||
| package eu.mhsl.craftattack.core.util.api; | package eu.mhsl.craftattack.spawn.common.api; | ||||||
| 
 | 
 | ||||||
| import eu.mhsl.craftattack.core.config.Configuration; | import eu.mhsl.craftattack.spawn.core.config.Configuration; | ||||||
| import org.apache.http.client.utils.URIBuilder; | import org.apache.http.client.utils.URIBuilder; | ||||||
| import org.bukkit.configuration.ConfigurationSection; | import org.bukkit.configuration.ConfigurationSection; | ||||||
| 
 | 
 | ||||||
| import java.net.URI; | import java.net.URI; | ||||||
| import java.net.URISyntaxException; | import java.net.URISyntaxException; | ||||||
|  | import java.net.http.HttpRequest; | ||||||
| import java.util.Objects; | import java.util.Objects; | ||||||
| 
 | 
 | ||||||
| public class WebsiteApiUtil { | public class CraftAttackApi { | ||||||
|     private final static ConfigurationSection apiConfig = Objects.requireNonNull(Configuration.cfg.getConfigurationSection("api")); |     private final static ConfigurationSection apiConfig = Objects.requireNonNull(Configuration.cfg.getConfigurationSection("api")); | ||||||
|     public final static String basePath = apiConfig.getString("baseurl"); |     public final static String basePath = apiConfig.getString("baseurl"); | ||||||
|     public final static String apiSecret = apiConfig.getString("secret"); |     public final static String apiSecret = apiConfig.getString("secret"); | ||||||
| @@ -25,4 +26,8 @@ public class WebsiteApiUtil { | |||||||
|     public static void withAuthorizationSecret(URIBuilder builder) { |     public static void withAuthorizationSecret(URIBuilder builder) { | ||||||
|         builder.addParameter("secret", apiSecret); |         builder.addParameter("secret", apiSecret); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     public static void withAuthorizationHeader(HttpRequest.Builder builder) { | ||||||
|  |         builder.header("Authorization", apiSecret); | ||||||
|  |     } | ||||||
| } | } | ||||||
| @@ -0,0 +1,28 @@ | |||||||
|  | package eu.mhsl.craftattack.spawn.common.api; | ||||||
|  |  | ||||||
|  | import eu.mhsl.craftattack.spawn.core.config.Configuration; | ||||||
|  | import org.bukkit.configuration.ConfigurationSection; | ||||||
|  |  | ||||||
|  | import java.net.URI; | ||||||
|  | import java.net.URISyntaxException; | ||||||
|  | import java.net.http.HttpRequest; | ||||||
|  | import java.util.Objects; | ||||||
|  |  | ||||||
|  | public class VaroApi { | ||||||
|  |     private final static ConfigurationSection apiConfig = Objects.requireNonNull(Configuration.cfg.getConfigurationSection("varoApi")); | ||||||
|  |     public final static String basePath = apiConfig.getString("endpoint"); | ||||||
|  |     public final static String apiSecret = apiConfig.getString("auth"); | ||||||
|  |  | ||||||
|  |     public static URI getBaseUri() { | ||||||
|  |         Objects.requireNonNull(basePath); | ||||||
|  |         try { | ||||||
|  |             return new URI(basePath); | ||||||
|  |         } catch(URISyntaxException e) { | ||||||
|  |             throw new RuntimeException(e); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static void authorizationHeader(HttpRequest.Builder builder) { | ||||||
|  |         builder.header("Authorization", apiSecret); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,26 @@ | |||||||
|  | package eu.mhsl.craftattack.spawn.common.api.repositories; | ||||||
|  |  | ||||||
|  | import eu.mhsl.craftattack.spawn.core.api.client.ReqResp; | ||||||
|  | import eu.mhsl.craftattack.spawn.common.api.CraftAttackApi; | ||||||
|  | import java.util.UUID; | ||||||
|  |  | ||||||
|  | public class CraftAttackReportRepository extends ReportRepository { | ||||||
|  |     public CraftAttackReportRepository() { | ||||||
|  |         super(CraftAttackApi.getBaseUri(), new RequestModifier(null, CraftAttackApi::withAuthorizationHeader)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public ReqResp<PlayerReports> queryReports(UUID player) { | ||||||
|  |         return this.get( | ||||||
|  |             "users/%s/reports".formatted(player.toString()), | ||||||
|  |             PlayerReports.class | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public ReqResp<ReportUrl> createReport(ReportCreationInfo data) { | ||||||
|  |         return this.post( | ||||||
|  |             "reports", | ||||||
|  |             data, | ||||||
|  |             ReportUrl.class | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,41 @@ | |||||||
|  | package eu.mhsl.craftattack.spawn.common.api.repositories; | ||||||
|  |  | ||||||
|  | import eu.mhsl.craftattack.spawn.core.api.client.HttpRepository; | ||||||
|  | import eu.mhsl.craftattack.spawn.core.api.client.RepositoryLoader; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  | import org.jetbrains.annotations.Nullable; | ||||||
|  |  | ||||||
|  | import java.net.URI; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.UUID; | ||||||
|  |  | ||||||
|  | @RepositoryLoader.Abstraction | ||||||
|  | public abstract class ReportRepository extends HttpRepository { | ||||||
|  |     public ReportRepository(URI basePath, RequestModifier... baseRequestModifier) { | ||||||
|  |         super(basePath, baseRequestModifier); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public record ReportCreationInfo(@NotNull UUID reporter, @Nullable UUID reported, String reason) { | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public record ReportUrl(@NotNull String url) { | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public record PlayerReports( | ||||||
|  |         List<Report> from_self, | ||||||
|  |         List<Report> to_self | ||||||
|  |     ) { | ||||||
|  |         public record Report( | ||||||
|  |             @Nullable UUID reported, | ||||||
|  |             @NotNull String reason, | ||||||
|  |             @Nullable Long created, | ||||||
|  |             @Nullable Status status, | ||||||
|  |             @NotNull String url | ||||||
|  |         ) { | ||||||
|  |             public enum Status { | ||||||
|  |                 open, | ||||||
|  |                 closed, | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,45 @@ | |||||||
|  | package eu.mhsl.craftattack.spawn.common.api.repositories; | ||||||
|  |  | ||||||
|  | import eu.mhsl.craftattack.spawn.common.api.VaroApi; | ||||||
|  | import eu.mhsl.craftattack.spawn.core.api.client.ReqResp; | ||||||
|  | import org.apache.commons.lang3.NotImplementedException; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  | import org.jetbrains.annotations.Nullable; | ||||||
|  |  | ||||||
|  | import java.util.UUID; | ||||||
|  |  | ||||||
|  | public class VaroReportRepository extends ReportRepository { | ||||||
|  |     public VaroReportRepository() { | ||||||
|  |         super(VaroApi.getBaseUri(), new RequestModifier(null, VaroApi::authorizationHeader)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public ReqResp<PlayerReports> queryReports(UUID player) { | ||||||
|  |         throw new NotImplementedException("Report querying is not supported in Varo!"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public ReqResp<ReportUrl> createReport(ReportCreationInfo data) { | ||||||
|  |         return this.post( | ||||||
|  |             "report", | ||||||
|  |             data, | ||||||
|  |             ReportUrl.class | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public record StrikeCreationInfo( | ||||||
|  |         @Nullable UUID reporter, // null for automatic creations | ||||||
|  |         @NotNull UUID reported, | ||||||
|  |         @NotNull String reason, | ||||||
|  |         @Nullable String body, | ||||||
|  |         @Nullable String notice, | ||||||
|  |         @Nullable String statement, | ||||||
|  |         int strike_reason_id // internal strike mapping | ||||||
|  |     ) { | ||||||
|  |     } | ||||||
|  |     public ReqResp<Void> createStrike(StrikeCreationInfo data) { | ||||||
|  |         return this.put( | ||||||
|  |             "report", | ||||||
|  |             data, | ||||||
|  |             Void.class | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,21 @@ | |||||||
|  | package eu.mhsl.craftattack.spawn.common.appliances.gameplay.cordinateDisplay; | ||||||
|  |  | ||||||
|  | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; | ||||||
|  | import org.bukkit.event.EventHandler; | ||||||
|  | import org.bukkit.event.player.PlayerJoinEvent; | ||||||
|  | import org.bukkit.event.player.PlayerMoveEvent; | ||||||
|  |  | ||||||
|  | public class CoordinateChangedListener extends ApplianceListener<CoordinateDisplay> { | ||||||
|  |     @EventHandler | ||||||
|  |     public void onJoin(PlayerJoinEvent event) { | ||||||
|  |         this.getAppliance().updateEnabled(event.getPlayer()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @EventHandler | ||||||
|  |     public void onMove(PlayerMoveEvent event) { | ||||||
|  |         if(!this.getAppliance().isEnabled(event.getPlayer())) return; | ||||||
|  |         boolean hasChangedOrientation = this.getAppliance().hasChangedDirection(event.getFrom(), event.getTo()); | ||||||
|  |         if(!event.hasChangedBlock() && !hasChangedOrientation) return; | ||||||
|  |         this.getAppliance().sendCoordinates(event.getPlayer()); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,93 @@ | |||||||
|  | package eu.mhsl.craftattack.spawn.common.appliances.gameplay.cordinateDisplay; | ||||||
|  |  | ||||||
|  | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings; | ||||||
|  | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
|  | import eu.mhsl.craftattack.spawn.core.util.text.DataSizeConverter; | ||||||
|  | import eu.mhsl.craftattack.spawn.core.util.world.WorldUtils; | ||||||
|  | import net.kyori.adventure.text.Component; | ||||||
|  | import net.kyori.adventure.text.format.NamedTextColor; | ||||||
|  | import org.bukkit.Location; | ||||||
|  | import org.bukkit.entity.Player; | ||||||
|  | import org.bukkit.event.Listener; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  |  | ||||||
|  | import java.util.*; | ||||||
|  |  | ||||||
|  | public class CoordinateDisplay extends Appliance { | ||||||
|  |     Map<Player, CoordinateDisplaySetting.CoordinateDisplayConfiguration> enabledPlayers = new WeakHashMap<>(); | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void onEnable() { | ||||||
|  |         Settings.instance().declareSetting(CoordinateDisplaySetting.class); | ||||||
|  |         Settings.instance().addChangeListener(CoordinateDisplaySetting.class, this::updateEnabled); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void updateEnabled(Player player) { | ||||||
|  |         CoordinateDisplaySetting.CoordinateDisplayConfiguration configuration = Settings.instance().getSetting( | ||||||
|  |             player, | ||||||
|  |             Settings.Key.CoordinateDisplay, | ||||||
|  |             CoordinateDisplaySetting.CoordinateDisplayConfiguration.class | ||||||
|  |         ); | ||||||
|  |         this.enabledPlayers.put(player, configuration); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public boolean isEnabled(Player player) { | ||||||
|  |         return Optional.ofNullable(this.enabledPlayers.get(player)) | ||||||
|  |             .map(CoordinateDisplaySetting.CoordinateDisplayConfiguration::anyEnabled) | ||||||
|  |             .orElse(false); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void sendCoordinates(Player player) { | ||||||
|  |         CoordinateDisplaySetting.CoordinateDisplayConfiguration config = this.enabledPlayers.get(player); | ||||||
|  |         List<Component> components = new ArrayList<>(); | ||||||
|  |  | ||||||
|  |         if (config.coordinates()) { | ||||||
|  |             components.add(Component.text("\uD83C\uDF0E ", NamedTextColor.GOLD)); | ||||||
|  |             components.add(Component.text(String.format( | ||||||
|  |                 "%d %d %d", | ||||||
|  |                 player.getLocation().getBlockX(), | ||||||
|  |                 player.getLocation().getBlockY(), | ||||||
|  |                 player.getLocation().getBlockZ() | ||||||
|  |             ))); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (config.direction()) { | ||||||
|  |             if (!components.isEmpty()) { | ||||||
|  |                 components.add(Component.text(" | ", NamedTextColor.GRAY)); | ||||||
|  |             } | ||||||
|  |             components.add(Component.text("\uD83E\uDDED ", NamedTextColor.GOLD)); | ||||||
|  |             components.add(Component.text(DataSizeConverter.getCardinalDirection(player.getLocation()))); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (config.time()) { | ||||||
|  |             if (!components.isEmpty()) { | ||||||
|  |                 components.add(Component.text(" | ", NamedTextColor.GRAY)); | ||||||
|  |             } | ||||||
|  |             components.add(Component.text("⏱ ", NamedTextColor.GOLD)); | ||||||
|  |             components.add(Component.text(WorldUtils.getGameTime(player.getWorld()))); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!components.isEmpty()) { | ||||||
|  |             Component actionBar = Component.empty(); | ||||||
|  |             for (Component component : components) { | ||||||
|  |                 actionBar = actionBar.append(component); | ||||||
|  |             } | ||||||
|  |             player.sendActionBar(actionBar); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     public boolean hasChangedDirection(Location previous, Location next) { | ||||||
|  |         return !Objects.equals( | ||||||
|  |             DataSizeConverter.getCardinalDirection(previous), | ||||||
|  |             DataSizeConverter.getCardinalDirection(next) | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     protected @NotNull List<Listener> listeners() { | ||||||
|  |         return List.of( | ||||||
|  |             new CoordinateChangedListener() | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,53 @@ | |||||||
|  | package eu.mhsl.craftattack.spawn.common.appliances.gameplay.cordinateDisplay; | ||||||
|  |  | ||||||
|  | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.CategorizedSetting; | ||||||
|  | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.SettingCategory; | ||||||
|  | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings; | ||||||
|  | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.datatypes.MultiBoolSetting; | ||||||
|  | import org.bukkit.Material; | ||||||
|  |  | ||||||
|  | public class CoordinateDisplaySetting extends MultiBoolSetting<CoordinateDisplaySetting.CoordinateDisplayConfiguration> implements CategorizedSetting { | ||||||
|  |     public CoordinateDisplaySetting() { | ||||||
|  |         super(Settings.Key.CoordinateDisplay); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public SettingCategory category() { | ||||||
|  |         return SettingCategory.Gameplay; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public record CoordinateDisplayConfiguration( | ||||||
|  |         @DisplayName("Koordinaten") boolean coordinates, | ||||||
|  |         @DisplayName("Richtung") boolean direction, | ||||||
|  |         @DisplayName("Zeit") boolean time | ||||||
|  |     ) { | ||||||
|  |         public boolean anyEnabled() { | ||||||
|  |             return this.coordinates || this.direction || this.time; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     protected String title() { | ||||||
|  |         return "Koordinatenanzeige"; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     protected String description() { | ||||||
|  |         return "Zeige deine aktuelle Position über der Hotbar an"; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     protected Material icon() { | ||||||
|  |         return Material.RECOVERY_COMPASS; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     protected CoordinateDisplayConfiguration defaultValue() { | ||||||
|  |         return new CoordinateDisplayConfiguration(false, false, false); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Class<?> dataType() { | ||||||
|  |         return CoordinateDisplayConfiguration.class; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,7 +1,7 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.internal.debug; | package eu.mhsl.craftattack.spawn.common.appliances.internal.debug; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.Appliance; | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.internal.debug.command.AppliancesCommand; | import eu.mhsl.craftattack.spawn.common.appliances.internal.debug.command.AppliancesCommand; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.internal.debug.command.UserInfoCommand; | import eu.mhsl.craftattack.spawn.common.appliances.internal.debug.command.UserInfoCommand; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
|   | |||||||
| @@ -1,9 +1,9 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.internal.debug.command; | package eu.mhsl.craftattack.spawn.common.appliances.internal.debug.command; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.Main; | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.internal.debug.Debug; | import eu.mhsl.craftattack.spawn.common.appliances.internal.debug.Debug; | ||||||
| import eu.mhsl.craftattack.core.util.text.ComponentUtil; | import eu.mhsl.craftattack.spawn.core.util.text.ComponentUtil; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.ComponentBuilder; | import net.kyori.adventure.text.ComponentBuilder; | ||||||
| import net.kyori.adventure.text.TextComponent; | import net.kyori.adventure.text.TextComponent; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.internal.debug.command; | package eu.mhsl.craftattack.spawn.common.appliances.internal.debug.command; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.internal.debug.Debug; | import eu.mhsl.craftattack.spawn.common.appliances.internal.debug.Debug; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.event.ClickEvent; | import net.kyori.adventure.text.event.ClickEvent; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.internal.titleClear; | package eu.mhsl.craftattack.spawn.common.appliances.internal.titleClear; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.Appliance; | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
| import org.bukkit.entity.Player; | import org.bukkit.entity.Player; | ||||||
| import org.bukkit.event.Listener; | import org.bukkit.event.Listener; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.internal.titleClear; | package eu.mhsl.craftattack.spawn.common.appliances.internal.titleClear; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceListener; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; | ||||||
| import org.bukkit.event.EventHandler; | import org.bukkit.event.EventHandler; | ||||||
| import org.bukkit.event.player.PlayerJoinEvent; | import org.bukkit.event.player.PlayerJoinEvent; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -0,0 +1,34 @@ | |||||||
|  | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.adminMarker; | ||||||
|  |  | ||||||
|  | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
|  | import eu.mhsl.craftattack.spawn.core.api.server.HttpServer; | ||||||
|  | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
|  | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.displayName.DisplayName; | ||||||
|  | import net.kyori.adventure.text.format.TextColor; | ||||||
|  | import org.bukkit.Bukkit; | ||||||
|  | import org.bukkit.Color; | ||||||
|  | import org.bukkit.OfflinePlayer; | ||||||
|  | import org.bukkit.entity.Player; | ||||||
|  | import org.jetbrains.annotations.Nullable; | ||||||
|  |  | ||||||
|  | import java.util.UUID; | ||||||
|  |  | ||||||
|  | public class AdminMarker extends Appliance implements DisplayName.Colored { | ||||||
|  |     public final static String adminPermission = "admin"; | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public @Nullable TextColor getNameColor(Player player) { | ||||||
|  |         if(player.hasPermission(adminPermission)) | ||||||
|  |             return TextColor.color(Color.AQUA.asRGB()); // TODO read permission from config | ||||||
|  |         return TextColor.color(Color.WHITE.asRGB()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void httpApi(HttpServer.ApiBuilder apiBuilder) { | ||||||
|  |         apiBuilder.get("isAdmin", request -> { | ||||||
|  |             OfflinePlayer player = Bukkit.getOfflinePlayer(UUID.fromString(request.queryParams("player"))); | ||||||
|  |             Main.logger().info(String.format("Adminstatus requested for %s, response: %s", player.getUniqueId(), player.isOp())); | ||||||
|  |             return player.isOp(); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,7 +1,7 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.chatMention; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.chatMention; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.Main; | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
| import eu.mhsl.craftattack.core.appliance.Appliance; | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings; | ||||||
| import net.kyori.adventure.sound.Sound; | import net.kyori.adventure.sound.Sound; | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
|   | |||||||
| @@ -1,10 +1,10 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.chatMention; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.chatMention; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.Main; | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceListener; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.chatMessages.ChatMessages; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.chatMessages.ChatMessages; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings; | ||||||
| import eu.mhsl.craftattack.core.util.text.ComponentUtil; | import eu.mhsl.craftattack.spawn.core.util.text.ComponentUtil; | ||||||
| import io.papermc.paper.event.player.AsyncChatDecorateEvent; | import io.papermc.paper.event.player.AsyncChatDecorateEvent; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.format.NamedTextColor; | import net.kyori.adventure.text.format.NamedTextColor; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.chatMessages; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.chatMessages; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.Appliance; | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.event.ClickEvent; | import net.kyori.adventure.text.event.ClickEvent; | ||||||
|   | |||||||
| @@ -1,8 +1,8 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.chatMessages; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.chatMessages; | ||||||
|  |  | ||||||
| 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 eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings; | ||||||
| import eu.mhsl.craftattack.core.util.IteratorUtil; | import eu.mhsl.craftattack.spawn.core.util.IteratorUtil; | ||||||
| import io.papermc.paper.event.player.AsyncChatEvent; | import io.papermc.paper.event.player.AsyncChatEvent; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.format.NamedTextColor; | import net.kyori.adventure.text.format.NamedTextColor; | ||||||
| @@ -21,16 +21,17 @@ class ChatMessagesListener extends ApplianceListener<ChatMessages> { | |||||||
|     public void onPlayerChatEvent(AsyncChatEvent event) { |     public void onPlayerChatEvent(AsyncChatEvent event) { | ||||||
|         event.renderer( |         event.renderer( | ||||||
|             (source, sourceDisplayName, message, viewer) -> |             (source, sourceDisplayName, message, viewer) -> | ||||||
|                 Component.text("") |                 Component.text() | ||||||
|                     .append(this.getAppliance().getReportablePlayerName(source)) |                     .append(this.getAppliance().getReportablePlayerName(source)) | ||||||
|                     .append(Component.text(" > ").color(TextColor.color(Color.GRAY.asRGB()))) |                     .append(Component.text(" > ").color(TextColor.color(Color.GRAY.asRGB()))) | ||||||
|                     .append(message).color(TextColor.color(Color.SILVER.asRGB())) |                     .append(message).color(TextColor.color(Color.SILVER.asRGB())) | ||||||
|  |                     .build() | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @EventHandler(priority = EventPriority.HIGH) |     @EventHandler(priority = EventPriority.HIGH) | ||||||
|     public void onPlayerJoin(PlayerJoinEvent event) { |     public void onPlayerJoin(PlayerJoinEvent event) { | ||||||
|         event.joinMessage(null); |         if(event.joinMessage() == null) return; | ||||||
|         IteratorUtil.onlinePlayers(player -> { |         IteratorUtil.onlinePlayers(player -> { | ||||||
|             if(!Settings.instance().getSetting(player, Settings.Key.ShowJoinAndLeaveMessages, Boolean.class)) return; |             if(!Settings.instance().getSetting(player, Settings.Key.ShowJoinAndLeaveMessages, Boolean.class)) return; | ||||||
|             player.sendMessage( |             player.sendMessage( | ||||||
| @@ -43,7 +44,7 @@ class ChatMessagesListener extends ApplianceListener<ChatMessages> { | |||||||
|  |  | ||||||
|     @EventHandler |     @EventHandler | ||||||
|     public void onPlayerLeave(PlayerQuitEvent event) { |     public void onPlayerLeave(PlayerQuitEvent event) { | ||||||
|         event.quitMessage(null); |         if(event.quitMessage() == null) return; | ||||||
|         IteratorUtil.onlinePlayers(player -> { |         IteratorUtil.onlinePlayers(player -> { | ||||||
|             if(!Settings.instance().getSetting(player, Settings.Key.ShowJoinAndLeaveMessages, Boolean.class)) return; |             if(!Settings.instance().getSetting(player, Settings.Key.ShowJoinAndLeaveMessages, Boolean.class)) return; | ||||||
|             player.sendMessage( |             player.sendMessage( | ||||||
|   | |||||||
| @@ -1,14 +1,9 @@ | |||||||
| package eu.mhsl.craftattack.spawn.craftattack.appliances.metaGameplay.displayName; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.displayName; | ||||||
| 
 | 
 | ||||||
| import eu.mhsl.craftattack.core.Main; | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
| import eu.mhsl.craftattack.core.appliance.Appliance; | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
| import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.outlawed.Outlawed; | import eu.mhsl.craftattack.spawn.core.util.server.Floodgate; | ||||||
| import eu.mhsl.craftattack.spawn.craftattack.appliances.metaGameplay.adminMarker.AdminMarker; | import eu.mhsl.craftattack.spawn.core.util.text.ComponentUtil; | ||||||
| import eu.mhsl.craftattack.spawn.craftattack.appliances.metaGameplay.afkTag.AfkTag; |  | ||||||
| import eu.mhsl.craftattack.spawn.craftattack.appliances.metaGameplay.sleepTag.SleepTag; |  | ||||||
| import eu.mhsl.craftattack.spawn.craftattack.appliances.metaGameplay.yearRank.YearRank; |  | ||||||
| import eu.mhsl.craftattack.core.util.server.Floodgate; |  | ||||||
| import eu.mhsl.craftattack.core.util.text.ComponentUtil; |  | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.ComponentBuilder; | import net.kyori.adventure.text.ComponentBuilder; | ||||||
| import net.kyori.adventure.text.TextComponent; | import net.kyori.adventure.text.TextComponent; | ||||||
| @@ -16,11 +11,12 @@ import net.kyori.adventure.text.event.HoverEvent; | |||||||
| import net.kyori.adventure.text.format.NamedTextColor; | import net.kyori.adventure.text.format.NamedTextColor; | ||||||
| import net.kyori.adventure.text.format.TextColor; | import net.kyori.adventure.text.format.TextColor; | ||||||
| import org.bukkit.entity.Player; | import org.bukkit.entity.Player; | ||||||
|  | import org.bukkit.event.Listener; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Nullable; | import org.jetbrains.annotations.Nullable; | ||||||
| 
 | 
 | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Objects; | import java.util.Objects; | ||||||
| import java.util.function.Supplier; |  | ||||||
| import java.util.logging.Level; | import java.util.logging.Level; | ||||||
| 
 | 
 | ||||||
| public class DisplayName extends Appliance { | public class DisplayName extends Appliance { | ||||||
| @@ -29,18 +25,33 @@ public class DisplayName extends Appliance { | |||||||
|         Component getNamePrefix(Player player); |         Component getNamePrefix(Player player); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public interface Colored { | ||||||
|  |         @Nullable | ||||||
|  |         TextColor getNameColor(Player player); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public void update(Player player) { |     public void update(Player player) { | ||||||
|         TextColor playerColor = this.queryAppliance(AdminMarker.class).getPlayerColor(player); |         List<Colored> coloring = Main.instance().getAppliances().stream() | ||||||
|         List<Supplier<Prefixed>> prefixes = List.of( |             .filter(appliance -> appliance instanceof Colored) | ||||||
|             () -> this.queryAppliance(Outlawed.class), |             .map(appliance -> (Colored) appliance) | ||||||
|             () -> this.queryAppliance(YearRank.class), |             .toList(); | ||||||
|             () -> this.queryAppliance(AfkTag.class), | 
 | ||||||
|             () -> this.queryAppliance(SleepTag.class) |         if(coloring.size() > 1) throw new IllegalStateException( | ||||||
|  |             "There are two or more appliances which provide coloring for player names. This is currently not supported!" | ||||||
|         ); |         ); | ||||||
| 
 | 
 | ||||||
|  |         TextColor playerColor = coloring.isEmpty() | ||||||
|  |             ? NamedTextColor.WHITE | ||||||
|  |             : coloring.getFirst().getNameColor(player); | ||||||
|  | 
 | ||||||
|  |         List<Prefixed> prefixes = Main.instance().getAppliances().stream() | ||||||
|  |             .filter(appliance -> appliance instanceof Prefixed) | ||||||
|  |             .map(appliance -> (Prefixed) appliance) | ||||||
|  |             .toList(); | ||||||
|  | 
 | ||||||
|         ComponentBuilder<TextComponent, TextComponent.Builder> playerName = Component.text(); |         ComponentBuilder<TextComponent, TextComponent.Builder> playerName = Component.text(); | ||||||
|         prefixes.stream() |         prefixes.stream() | ||||||
|             .map(prefixed -> prefixed.get().getNamePrefix(player)) |             .map(prefixed -> prefixed.getNamePrefix(player)) | ||||||
|             .filter(Objects::nonNull) |             .filter(Objects::nonNull) | ||||||
|             .forEach(prefix -> playerName |             .forEach(prefix -> playerName | ||||||
|                 .append(prefix) |                 .append(prefix) | ||||||
| @@ -72,4 +83,9 @@ public class DisplayName extends Appliance { | |||||||
|             Main.instance().getLogger().log(Level.SEVERE, e, e::getMessage); |             Main.instance().getLogger().log(Level.SEVERE, e, e::getMessage); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     protected @NotNull List<Listener> listeners() { | ||||||
|  |         return List.of(new DisplayNameUpdateListener()); | ||||||
|  |     } | ||||||
| } | } | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.craftattack.appliances.metaGameplay.displayName; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.displayName; | ||||||
| 
 | 
 | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceListener; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; | ||||||
| import org.bukkit.event.EventHandler; | import org.bukkit.event.EventHandler; | ||||||
| import org.bukkit.event.EventPriority; | import org.bukkit.event.EventPriority; | ||||||
| import org.bukkit.event.player.PlayerJoinEvent; | import org.bukkit.event.player.PlayerJoinEvent; | ||||||
| @@ -1,7 +1,7 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.help; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.help; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.Appliance; | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.help.command.DiscordCommand; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.help.command.DiscordCommand; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.help.command.HelpCommand; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.help.command.HelpCommand; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.help.command.SpawnCommand; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.help.command.SpawnCommand; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.help.command; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.help.command; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.help.Help; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.help.Help; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.event.ClickEvent; | import net.kyori.adventure.text.event.ClickEvent; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.help.command; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.help.command; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.help.Help; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.help.Help; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.format.NamedTextColor; | import net.kyori.adventure.text.format.NamedTextColor; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.help.command; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.help.command; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.help.Help; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.help.Help; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.format.NamedTextColor; | import net.kyori.adventure.text.format.NamedTextColor; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.help.command; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.help.command; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.help.Help; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.help.Help; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.format.NamedTextColor; | import net.kyori.adventure.text.format.NamedTextColor; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.Main; | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
| import net.kyori.adventure.bossbar.BossBar; | import net.kyori.adventure.bossbar.BossBar; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.util.Ticks; | import net.kyori.adventure.util.Ticks; | ||||||
| @@ -13,6 +13,7 @@ import java.time.temporal.ChronoUnit; | |||||||
| public abstract class Bar { | public abstract class Bar { | ||||||
|     private BossBar bossBar; |     private BossBar bossBar; | ||||||
|     private final BukkitTask updateTask; |     private final BukkitTask updateTask; | ||||||
|  |     public static String name; | ||||||
|  |  | ||||||
|     public Bar() { |     public Bar() { | ||||||
|         long refreshRateInTicks = this.refresh().get(ChronoUnit.SECONDS) * Ticks.TICKS_PER_SECOND; |         long refreshRateInTicks = this.refresh().get(ChronoUnit.SECONDS) * Ticks.TICKS_PER_SECOND; | ||||||
| @@ -32,7 +33,7 @@ public abstract class Bar { | |||||||
|     private BossBar createBar() { |     private BossBar createBar() { | ||||||
|         return BossBar.bossBar( |         return BossBar.bossBar( | ||||||
|             this.title(), |             this.title(), | ||||||
|             this.correctedProgress(), |             this.clampedProgress(), | ||||||
|             this.color(), |             this.color(), | ||||||
|             this.overlay() |             this.overlay() | ||||||
|         ); |         ); | ||||||
| @@ -43,7 +44,7 @@ public abstract class Bar { | |||||||
|  |  | ||||||
|         this.beforeRefresh(); |         this.beforeRefresh(); | ||||||
|         this.bossBar.name(this.title()); |         this.bossBar.name(this.title()); | ||||||
|         this.bossBar.progress(this.correctedProgress()); |         this.bossBar.progress(this.clampedProgress()); | ||||||
|         this.bossBar.color(this.color()); |         this.bossBar.color(this.color()); | ||||||
|         this.bossBar.overlay(this.overlay()); |         this.bossBar.overlay(this.overlay()); | ||||||
|     } |     } | ||||||
| @@ -52,7 +53,7 @@ public abstract class Bar { | |||||||
|         this.updateTask.cancel(); |         this.updateTask.cancel(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private float correctedProgress() { |     private float clampedProgress() { | ||||||
|         return Math.clamp(this.progress(), 0, 1); |         return Math.clamp(this.progress(), 0, 1); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,32 +0,0 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars; |  | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.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; |  | ||||||
|  |  | ||||||
| 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" -> this.getAppliance().hideAll(this.getPlayer()); |  | ||||||
|             case "show" -> this.getAppliance().show(this.getPlayer(), args[1]); |  | ||||||
|             case "hide" -> this.getAppliance().hide(this.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 this.getAppliance().getInfoBars().stream().map(Bar::name).toList(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -0,0 +1,51 @@ | |||||||
|  | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars; | ||||||
|  |  | ||||||
|  | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.CategorizedSetting; | ||||||
|  | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.SettingCategory; | ||||||
|  | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings; | ||||||
|  | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.datatypes.MultiBoolSetting; | ||||||
|  | import org.bukkit.Material; | ||||||
|  |  | ||||||
|  | public class InfoBarSetting extends MultiBoolSetting<InfoBarSetting.InfoBarConfiguration> implements CategorizedSetting { | ||||||
|  |     public InfoBarSetting() { | ||||||
|  |         super(Settings.Key.InfoBars); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public SettingCategory category() { | ||||||
|  |         return SettingCategory.Misc; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public record InfoBarConfiguration( | ||||||
|  |         @DisplayName("Millisekunden pro Tick") boolean mspt, | ||||||
|  |         @DisplayName("Spieler online") boolean playerCounter, | ||||||
|  |         @DisplayName("Ticks pro Sekunde") boolean tps | ||||||
|  |     ) {} | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     protected String title() { | ||||||
|  |         return "Informationsleisten"; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     protected String description() { | ||||||
|  |         return "Wähle anzuzeigende Informationsleisten aus"; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     protected Material icon() { | ||||||
|  |         return Material.COMMAND_BLOCK; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     protected InfoBarConfiguration defaultValue() { | ||||||
|  |         return new InfoBarConfiguration(false, false, false); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Class<?> dataType() { | ||||||
|  |         return InfoBarConfiguration.class; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -1,11 +1,13 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.Main; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings; | ||||||
| import eu.mhsl.craftattack.core.appliance.Appliance; | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
|  | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars.bars.MsptBar; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars.bars.MsptBar; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars.bars.PlayerCounterBar; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars.bars.PlayerCounterBar; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars.bars.TpsBar; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars.bars.TpsBar; | ||||||
|  | import org.bukkit.Bukkit; | ||||||
| import org.bukkit.NamespacedKey; | import org.bukkit.NamespacedKey; | ||||||
| import org.bukkit.entity.Player; | import org.bukkit.entity.Player; | ||||||
| import org.bukkit.event.Listener; | import org.bukkit.event.Listener; | ||||||
| @@ -24,39 +26,42 @@ public class InfoBars extends Appliance { | |||||||
|         new PlayerCounterBar() |         new PlayerCounterBar() | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|     public void showAll(Player player) { |     public void showAllEnabled(Player player) { | ||||||
|         this.getStoredBars(player).forEach(bar -> this.show(player, bar)); |         this.getEnabledBars(player).forEach(bar -> this.show(player, bar)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void hideAll(Player player) { |     public void hideAllEnabled(Player player) { | ||||||
|         this.getStoredBars(player).forEach(bar -> this.hide(player, bar)); |         this.getEnabledBars(player).forEach(bar -> this.hide(player, bar)); | ||||||
|         this.setStoredBars(player, List.of()); |         this.setEnabledBars(player, List.of()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void show(Player player, String bar) { |     public void show(Player player, String bar) { | ||||||
|         this.validateBarName(bar); |         this.validateBarName(bar); | ||||||
|         List<String> existingBars = new ArrayList<>(this.getStoredBars(player)); |         List<String> existingBars = new ArrayList<>(this.getEnabledBars(player)); | ||||||
|         existingBars.add(bar); |         existingBars.add(bar); | ||||||
|         player.showBossBar(this.getBarByName(bar).getBossBar()); |         player.showBossBar(this.getBarByName(bar).getBossBar()); | ||||||
|         this.setStoredBars(player, existingBars); |         this.setEnabledBars(player, existingBars); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void hide(Player player, String bar) { |     public void hide(Player player, String bar) { | ||||||
|         this.validateBarName(bar); |         this.validateBarName(bar); | ||||||
|         List<String> existingBars = new ArrayList<>(this.getStoredBars(player)); |         List<String> existingBars = new ArrayList<>(this.getEnabledBars(player)); | ||||||
|         existingBars.remove(bar); |         existingBars.remove(bar); | ||||||
|         player.hideBossBar(this.getBarByName(bar).getBossBar()); |         player.hideBossBar(this.getBarByName(bar).getBossBar()); | ||||||
|         this.setStoredBars(player, existingBars); |         this.setEnabledBars(player, existingBars); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private List<String> getStoredBars(Player player) { |     private List<String> getEnabledBars(Player player) { | ||||||
|         PersistentDataContainer container = player.getPersistentDataContainer(); |         PersistentDataContainer container = player.getPersistentDataContainer(); | ||||||
|         if(!container.has(this.infoBarKey)) return List.of(); |         if(!container.has(this.infoBarKey)) return List.of(); | ||||||
|         return container.get(this.infoBarKey, PersistentDataType.LIST.strings()); |         return container.get(this.infoBarKey, PersistentDataType.LIST.strings()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void setStoredBars(Player player, List<String> bars) { |     private void setEnabledBars(Player player, List<String> bars) { | ||||||
|         player.getPersistentDataContainer().set(this.infoBarKey, PersistentDataType.LIST.strings(), bars); |         Bukkit.getScheduler().runTask( | ||||||
|  |             Main.instance(), | ||||||
|  |             () -> player.getPersistentDataContainer().set(this.infoBarKey, PersistentDataType.LIST.strings(), bars) | ||||||
|  |         ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private Bar getBarByName(String name) { |     private Bar getBarByName(String name) { | ||||||
| @@ -71,8 +76,16 @@ public class InfoBars extends Appliance { | |||||||
|             throw new ApplianceCommand.Error(String.format("Ungültiger infobar name '%s'", name)); |             throw new ApplianceCommand.Error(String.format("Ungültiger infobar name '%s'", name)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public List<Bar> getInfoBars() { |     @Override | ||||||
|         return this.infoBars; |     public void onEnable() { | ||||||
|  |         Settings.instance().declareSetting(InfoBarSetting.class); | ||||||
|  |         Settings.instance().addChangeListener(InfoBarSetting.class, player -> { | ||||||
|  |             this.hideAllEnabled(player); | ||||||
|  |             InfoBarSetting.InfoBarConfiguration config = Settings.instance().getSetting(player, Settings.Key.InfoBars, InfoBarSetting.InfoBarConfiguration.class); | ||||||
|  |             if(config.mspt()) this.show(player, MsptBar.name); | ||||||
|  |             if(config.playerCounter()) this.show(player, PlayerCounterBar.name); | ||||||
|  |             if(config.tps()) this.show(player, TpsBar.name); | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -84,9 +97,4 @@ public class InfoBars extends Appliance { | |||||||
|     protected @NotNull List<Listener> listeners() { |     protected @NotNull List<Listener> listeners() { | ||||||
|         return List.of(new ShowPreviousBarsListener()); |         return List.of(new ShowPreviousBarsListener()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     protected @NotNull List<ApplianceCommand<?>> commands() { |  | ||||||
|         return List.of(new InfoBarCommand()); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,12 +1,12 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceListener; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; | ||||||
| import org.bukkit.event.EventHandler; | import org.bukkit.event.EventHandler; | ||||||
| import org.bukkit.event.player.PlayerJoinEvent; | import org.bukkit.event.player.PlayerJoinEvent; | ||||||
|  |  | ||||||
| class ShowPreviousBarsListener extends ApplianceListener<InfoBars> { | class ShowPreviousBarsListener extends ApplianceListener<InfoBars> { | ||||||
|     @EventHandler |     @EventHandler | ||||||
|     public void onJoin(PlayerJoinEvent event) { |     public void onJoin(PlayerJoinEvent event) { | ||||||
| //        this.getAppliance().showAll(event.getPlayer()); |         this.getAppliance().showAllEnabled(event.getPlayer()); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,8 +1,8 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars.bars; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars.bars; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars.Bar; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars.Bar; | ||||||
| import eu.mhsl.craftattack.core.util.statistics.ServerMonitor; | import eu.mhsl.craftattack.spawn.core.util.statistics.ServerMonitor; | ||||||
| import eu.mhsl.craftattack.core.util.text.ColorUtil; | import eu.mhsl.craftattack.spawn.core.util.text.ColorUtil; | ||||||
| import net.kyori.adventure.bossbar.BossBar; | import net.kyori.adventure.bossbar.BossBar; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.format.NamedTextColor; | import net.kyori.adventure.text.format.NamedTextColor; | ||||||
| @@ -10,6 +10,8 @@ import net.kyori.adventure.text.format.NamedTextColor; | |||||||
| import java.time.Duration; | import java.time.Duration; | ||||||
|  |  | ||||||
| public class MsptBar extends Bar { | public class MsptBar extends Bar { | ||||||
|  |     public static String name = "msptd"; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected Duration refresh() { |     protected Duration refresh() { | ||||||
|         return Duration.ofSeconds(3); |         return Duration.ofSeconds(3); | ||||||
| @@ -17,7 +19,7 @@ public class MsptBar extends Bar { | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected String name() { |     protected String name() { | ||||||
|         return "mspt"; |         return name; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -25,10 +27,10 @@ public class MsptBar extends Bar { | |||||||
|         return Component.text() |         return Component.text() | ||||||
|             .append(Component.text("M")) |             .append(Component.text("M")) | ||||||
|             .append(Component.text("illi", NamedTextColor.GRAY)) |             .append(Component.text("illi", NamedTextColor.GRAY)) | ||||||
|             .append(Component.text("S")) |             .append(Component.text("s")) | ||||||
|             .append(Component.text("econds ", NamedTextColor.GRAY)) |             .append(Component.text("ekunden ", NamedTextColor.GRAY)) | ||||||
|             .append(Component.text("P")) |             .append(Component.text("p")) | ||||||
|             .append(Component.text("er ", NamedTextColor.GRAY)) |             .append(Component.text("ro ", NamedTextColor.GRAY)) | ||||||
|             .append(Component.text("T")) |             .append(Component.text("T")) | ||||||
|             .append(Component.text("ick", NamedTextColor.GRAY)) |             .append(Component.text("ick", NamedTextColor.GRAY)) | ||||||
|             .append(Component.text(": ")) |             .append(Component.text(": ")) | ||||||
| @@ -43,7 +45,7 @@ public class MsptBar extends Bar { | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected BossBar.Color color() { |     protected BossBar.Color color() { | ||||||
|         return BossBar.Color.BLUE; |         return this.currentMSPT() <= 50 ? BossBar.Color.GREEN : BossBar.Color.RED; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|   | |||||||
| @@ -1,9 +1,9 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars.bars; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars.bars; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.Main; | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars.Bar; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars.Bar; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.tooling.playerlimit.PlayerLimit; | import eu.mhsl.craftattack.spawn.common.appliances.tooling.playerlimit.PlayerLimit; | ||||||
| import eu.mhsl.craftattack.core.util.text.ColorUtil; | import eu.mhsl.craftattack.spawn.core.util.text.ColorUtil; | ||||||
| import net.kyori.adventure.bossbar.BossBar; | import net.kyori.adventure.bossbar.BossBar; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.format.TextColor; | import net.kyori.adventure.text.format.TextColor; | ||||||
| @@ -12,6 +12,8 @@ import org.bukkit.Bukkit; | |||||||
| import java.time.Duration; | import java.time.Duration; | ||||||
|  |  | ||||||
| public class PlayerCounterBar extends Bar { | public class PlayerCounterBar extends Bar { | ||||||
|  |     public static String name = "playerCounter"; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected Duration refresh() { |     protected Duration refresh() { | ||||||
|         return Duration.ofSeconds(3); |         return Duration.ofSeconds(3); | ||||||
| @@ -19,7 +21,7 @@ public class PlayerCounterBar extends Bar { | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected String name() { |     protected String name() { | ||||||
|         return "playerCounter"; |         return name; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -38,7 +40,10 @@ public class PlayerCounterBar extends Bar { | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected BossBar.Color color() { |     protected BossBar.Color color() { | ||||||
|         return BossBar.Color.BLUE; |         int freeSlots = this.getMaxPlayerCount() - this.getCurrentPlayerCount(); | ||||||
|  |         return freeSlots <= 0 | ||||||
|  |             ? BossBar.Color.RED | ||||||
|  |             : freeSlots < 5 ? BossBar.Color.YELLOW : BossBar.Color.GREEN; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars.bars; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars.bars; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars.Bar; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.infoBars.Bar; | ||||||
| import eu.mhsl.craftattack.core.util.text.ColorUtil; | import eu.mhsl.craftattack.spawn.core.util.text.ColorUtil; | ||||||
| import net.kyori.adventure.bossbar.BossBar; | import net.kyori.adventure.bossbar.BossBar; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.format.NamedTextColor; | import net.kyori.adventure.text.format.NamedTextColor; | ||||||
| @@ -10,6 +10,8 @@ import org.bukkit.Bukkit; | |||||||
| import java.time.Duration; | import java.time.Duration; | ||||||
|  |  | ||||||
| public class TpsBar extends Bar { | public class TpsBar extends Bar { | ||||||
|  |     public static String name = "tps"; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected Duration refresh() { |     protected Duration refresh() { | ||||||
|         return Duration.ofSeconds(3); |         return Duration.ofSeconds(3); | ||||||
| @@ -17,7 +19,7 @@ public class TpsBar extends Bar { | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected String name() { |     protected String name() { | ||||||
|         return "tps"; |         return name; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -25,10 +27,10 @@ public class TpsBar extends Bar { | |||||||
|         return Component.text() |         return Component.text() | ||||||
|             .append(Component.text("T")) |             .append(Component.text("T")) | ||||||
|             .append(Component.text("icks ", NamedTextColor.GRAY)) |             .append(Component.text("icks ", NamedTextColor.GRAY)) | ||||||
|             .append(Component.text("P")) |             .append(Component.text("p")) | ||||||
|             .append(Component.text("er ", NamedTextColor.GRAY)) |             .append(Component.text("ro ", NamedTextColor.GRAY)) | ||||||
|             .append(Component.text("S")) |             .append(Component.text("S")) | ||||||
|             .append(Component.text("econds", NamedTextColor.GRAY)) |             .append(Component.text("ekunde", NamedTextColor.GRAY)) | ||||||
|             .append(Component.text(": ")) |             .append(Component.text(": ")) | ||||||
|             .append(Component.text(String.format("%.2f", this.currentTps()), ColorUtil.tpsColor(this.currentTps()))) |             .append(Component.text(String.format("%.2f", this.currentTps()), ColorUtil.tpsColor(this.currentTps()))) | ||||||
|             .build(); |             .build(); | ||||||
| @@ -41,7 +43,9 @@ public class TpsBar extends Bar { | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected BossBar.Color color() { |     protected BossBar.Color color() { | ||||||
|         return BossBar.Color.BLUE; |         return this.currentTps() >= 18 | ||||||
|  |             ? BossBar.Color.GREEN | ||||||
|  |             : this.currentTps() >= 15 ? BossBar.Color.YELLOW : BossBar.Color.RED; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|   | |||||||
| @@ -1,8 +1,8 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.privateMessage; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.privateMessage; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.Main; | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
| import eu.mhsl.craftattack.core.appliance.Appliance; | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.chatMessages.ChatMessages; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.chatMessages.ChatMessages; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.privateMessage.commands.PrivateMessageCommand; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.privateMessage.commands.PrivateMessageCommand; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.privateMessage.commands.PrivateReplyCommand; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.privateMessage.commands.PrivateReplyCommand; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.privateMessage.commands; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.privateMessage.commands; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.privateMessage.PrivateMessage; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.privateMessage.PrivateMessage; | ||||||
| import org.bukkit.command.Command; | import org.bukkit.command.Command; | ||||||
| import org.bukkit.command.CommandSender; | import org.bukkit.command.CommandSender; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.privateMessage.commands; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.privateMessage.commands; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.privateMessage.PrivateMessage; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.privateMessage.PrivateMessage; | ||||||
| import org.bukkit.command.Command; | import org.bukkit.command.Command; | ||||||
| import org.bukkit.command.CommandSender; | import org.bukkit.command.CommandSender; | ||||||
|   | |||||||
| @@ -1,10 +1,12 @@ | |||||||
| package eu.mhsl.craftattack.spawn.craftattack.appliances.metaGameplay.report; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.report; | ||||||
| 
 | 
 | ||||||
| import eu.mhsl.craftattack.core.Main; | import eu.mhsl.craftattack.spawn.common.api.repositories.ReportRepository; | ||||||
| import eu.mhsl.craftattack.core.api.client.ReqResp; | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
| import eu.mhsl.craftattack.core.api.client.repositories.ReportRepository; | import eu.mhsl.craftattack.spawn.core.api.client.ReqResp; | ||||||
| import eu.mhsl.craftattack.core.appliance.Appliance; | import eu.mhsl.craftattack.spawn.common.api.repositories.CraftAttackReportRepository; | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
|  | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
|  | import eu.mhsl.craftattack.spawn.core.util.text.ComponentUtil; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.ComponentBuilder; | import net.kyori.adventure.text.ComponentBuilder; | ||||||
| import net.kyori.adventure.text.TextComponent; | import net.kyori.adventure.text.TextComponent; | ||||||
| @@ -18,7 +20,9 @@ import org.jetbrains.annotations.NotNull; | |||||||
| import org.jetbrains.annotations.Nullable; | import org.jetbrains.annotations.Nullable; | ||||||
| 
 | 
 | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.Objects; | ||||||
| import java.util.Optional; | import java.util.Optional; | ||||||
|  | import java.util.function.Function; | ||||||
| 
 | 
 | ||||||
| public class Report extends Appliance { | public class Report extends Appliance { | ||||||
|     public static Component helpText() { |     public static Component helpText() { | ||||||
| @@ -36,7 +40,7 @@ public class Report extends Appliance { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public void reportToUnknown(@NotNull Player issuer) { |     public void reportToUnknown(@NotNull Player issuer) { | ||||||
|         ReportRepository.ReportCreationInfo request = new ReportRepository.ReportCreationInfo(issuer.getUniqueId(), null, ""); |         CraftAttackReportRepository.ReportCreationInfo request = new CraftAttackReportRepository.ReportCreationInfo(issuer.getUniqueId(), null, ""); | ||||||
|         Bukkit.getScheduler().runTaskAsynchronously( |         Bukkit.getScheduler().runTaskAsynchronously( | ||||||
|             Main.instance(), |             Main.instance(), | ||||||
|             () -> this.createReport(issuer, request) |             () -> this.createReport(issuer, request) | ||||||
| @@ -62,21 +66,22 @@ public class Report extends Appliance { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void createReport(Player issuer, ReportRepository.ReportCreationInfo reportRequest) { |     private void createReport(Player issuer, ReportRepository.ReportCreationInfo reportRequest) { | ||||||
|         ReqResp<ReportRepository.ReportUrl> createdReport = this.queryRepository(ReportRepository.class) |         ReqResp<ReportRepository.ReportUrl> createdReport = this.queryRepository(CraftAttackReportRepository.class) // TODO: Besser machen!! | ||||||
|             .createReport(reportRequest); |             .createReport(reportRequest); | ||||||
| 
 | 
 | ||||||
|         switch(createdReport.status()) { |         switch(createdReport.status()) { | ||||||
|  |             case 200: // varo-endpoint specific | ||||||
|             case 201: |             case 201: | ||||||
|                 issuer.sendMessage( |                 issuer.sendMessage( | ||||||
|                     Component.text() |                     Component.text() | ||||||
|                         .append(Component.text("\\/".repeat(20), NamedTextColor.DARK_GRAY)) |                         .append(Component.text("\\/".repeat(20), NamedTextColor.DARK_GRAY)) | ||||||
|                         .appendNewline() |                         .appendNewline() | ||||||
|                         .append(Component.text("⚠ Der Report muss über den folgenden Link fertiggestellt werden!", NamedTextColor.GOLD)) |                         .append(Component.text("⚠ Der Report muss über den folgenden Link fertiggestellt werden:", NamedTextColor.GOLD)) | ||||||
|                         .appendNewline() |                         .appendNewline() | ||||||
|                         .appendNewline() |                         .appendNewline() | ||||||
|                         .append( |                         .append( | ||||||
|                             Component |                             Component | ||||||
|                                 .text(createdReport.data().url(), NamedTextColor.GRAY) // URL mit Weltkugel-Emoji |                                 .text(createdReport.data().url(), NamedTextColor.GRAY) | ||||||
|                                 .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.OPEN_URL, createdReport.data().url())) |                                 .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.OPEN_URL, createdReport.data().url())) | ||||||
|                         ) |                         ) | ||||||
|                         .appendNewline() |                         .appendNewline() | ||||||
| @@ -112,7 +117,7 @@ public class Report extends Appliance { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public void queryReports(Player issuer) { |     public void queryReports(Player issuer) { | ||||||
|         ReqResp<ReportRepository.PlayerReports> userReports = this.queryRepository(ReportRepository.class) |         ReqResp<ReportRepository.PlayerReports> userReports = this.queryRepository(CraftAttackReportRepository.class) // TODO: Besser machen!! | ||||||
|             .queryReports(issuer.getUniqueId()); |             .queryReports(issuer.getUniqueId()); | ||||||
| 
 | 
 | ||||||
|         if(userReports.status() != 200) { |         if(userReports.status() != 200) { | ||||||
| @@ -126,43 +131,50 @@ public class Report extends Appliance { | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         List<ReportRepository.PlayerReports.Report> reports = userReports |         Function<List<ReportRepository.PlayerReports.Report>, List<ReportRepository.PlayerReports.Report>> filterClosed = reports -> reports.stream() | ||||||
|             .data() |             .filter(report -> Objects.equals(report.status(), ReportRepository.PlayerReports.Report.Status.closed)) | ||||||
|             .from_self() |             .toList(); | ||||||
|             .stream() |  | ||||||
|             .filter(report -> !report.draft()) |  | ||||||
|             .toList() |  | ||||||
|             .reversed(); |  | ||||||
| 
 | 
 | ||||||
|         if(reports.isEmpty()) { |         List<ReportRepository.PlayerReports.Report> reportsToOthers = filterClosed.apply(userReports.data().from_self()).reversed(); | ||||||
|             issuer.sendMessage( |         List<ReportRepository.PlayerReports.Report> reportsToSelf = filterClosed.apply(userReports.data().to_self()).reversed(); | ||||||
|                 Component.text() |  | ||||||
|                     .append(Component.text("Du hast noch niemanden reportet.", NamedTextColor.RED)) |  | ||||||
|                     .appendNewline() |  | ||||||
|                     .append(Component.text("Um jemanden zu melden, nutze /report", NamedTextColor.GRAY)) |  | ||||||
|             ); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         ComponentBuilder<TextComponent, TextComponent.Builder> component = Component.text() |         ComponentBuilder<TextComponent, TextComponent.Builder> component = Component.text() | ||||||
|             .append(Component.newline()) |             .append(Component.text( | ||||||
|             .append(Component.text("Von dir erstellte Reports: ", NamedTextColor.GOLD)) |                 !reportsToSelf.isEmpty() | ||||||
|             .appendNewline(); |                     ? "Du wurdest insgesamt %d mal von anderen Spielern gemeldet.".formatted(reportsToSelf.size()) | ||||||
|  |                     : "Du wurdest von keinem anderen Spieler gemeldet.", | ||||||
|  |                 NamedTextColor.GOLD) | ||||||
|  |             ); | ||||||
| 
 | 
 | ||||||
|         reports.forEach(report -> { |  | ||||||
|             component |  | ||||||
|                 .append(Component.text(" - ", NamedTextColor.WHITE)) |  | ||||||
|                 .append( |  | ||||||
|                     report.reported() != null |  | ||||||
|                         ? Component.text(report.reported().username(), NamedTextColor.WHITE) |  | ||||||
|                         : Component.text("Unbekannt", NamedTextColor.YELLOW) |  | ||||||
|                 ) |  | ||||||
|                 .append(Component.text(String.format(": %s", report.subject()), NamedTextColor.GRAY)) |  | ||||||
|                 .clickEvent(ClickEvent.openUrl(report.url())) |  | ||||||
|                 .hoverEvent(HoverEvent.showText(Component.text("Klicke, um den Report einzusehen.", NamedTextColor.GOLD))); |  | ||||||
|         component.appendNewline(); |         component.appendNewline(); | ||||||
|  | 
 | ||||||
|  |         component.append(Component.text("Von dir erstellte Reports: ", NamedTextColor.GOLD)); | ||||||
|  |         reportsToOthers.forEach(report -> { | ||||||
|  |             Component button = Component.text("[\uD83D\uDC41/\uD83D\uDD8A]") | ||||||
|  |                 .clickEvent(ClickEvent.openUrl(report.url())) | ||||||
|  |                 .hoverEvent(HoverEvent.showText(ComponentUtil.clickLink(report.url()))); | ||||||
|  | 
 | ||||||
|  |             Component reportedDisplayName = report.reported() != null | ||||||
|  |                 ? Component.text(Optional.ofNullable(Bukkit.getOfflinePlayer(report.reported()).getName()).orElse(report.reported().toString()), NamedTextColor.WHITE) | ||||||
|  |                 : Component.text("Unbekannt", NamedTextColor.YELLOW); | ||||||
|  | 
 | ||||||
|  |             component | ||||||
|  |                 .appendNewline() | ||||||
|  |                 .append(Component.text(" \u27A1 ", NamedTextColor.GRAY)) | ||||||
|  |                 .append(button) | ||||||
|  |                 .append(Component.text(" du gegen ", NamedTextColor.GRAY)) | ||||||
|  |                 .append(reportedDisplayName) | ||||||
|  |                 .append(Component.text(String.format(": %s", report.reason()), NamedTextColor.GRAY)); | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|  |         if(reportsToOthers.isEmpty()) { | ||||||
|  |             component | ||||||
|  |                 .appendNewline() | ||||||
|  |                 .append(Component.text("Du hast noch niemanden reportet.", NamedTextColor.RED)) | ||||||
|  |                 .appendNewline() | ||||||
|  |                 .append(Component.text("Um jemanden zu melden, nutze /report", NamedTextColor.GRAY)); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         issuer.sendMessage(component.build()); |         issuer.sendMessage(component.build()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @@ -1,7 +1,7 @@ | |||||||
| package eu.mhsl.craftattack.spawn.craftattack.appliances.metaGameplay.report; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.report; | ||||||
| 
 | 
 | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import eu.mhsl.craftattack.core.util.text.ComponentUtil; | import eu.mhsl.craftattack.spawn.core.util.text.ComponentUtil; | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
| import org.bukkit.OfflinePlayer; | import org.bukkit.OfflinePlayer; | ||||||
| import org.bukkit.command.Command; | import org.bukkit.command.Command; | ||||||
| @@ -1,8 +1,8 @@ | |||||||
| package eu.mhsl.craftattack.spawn.craftattack.appliances.metaGameplay.report; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.report; | ||||||
| 
 | 
 | ||||||
| import eu.mhsl.craftattack.core.Main; | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import eu.mhsl.craftattack.core.util.text.ComponentUtil; | import eu.mhsl.craftattack.spawn.core.util.text.ComponentUtil; | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
| import org.bukkit.command.Command; | import org.bukkit.command.Command; | ||||||
| import org.bukkit.command.CommandSender; | import org.bukkit.command.CommandSender; | ||||||
| @@ -1,11 +1,12 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.Main; | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
| import eu.mhsl.craftattack.core.appliance.Appliance; | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.datatypes.Setting; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.datatypes.Setting; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.listeners.OpenSettingsShortcutListener; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.listeners.OpenSettingsShortcutListener; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.listeners.SettingsInventoryListener; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.listeners.SettingsInventoryListener; | ||||||
|  | import eu.mhsl.craftattack.spawn.core.util.world.InteractSounds; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
| import org.bukkit.entity.Player; | import org.bukkit.entity.Player; | ||||||
| @@ -16,6 +17,7 @@ import org.jetbrains.annotations.NotNull; | |||||||
| import java.lang.reflect.InvocationTargetException; | import java.lang.reflect.InvocationTargetException; | ||||||
| import java.util.*; | import java.util.*; | ||||||
| import java.util.concurrent.atomic.AtomicInteger; | import java.util.concurrent.atomic.AtomicInteger; | ||||||
|  | import java.util.function.Consumer; | ||||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||||
|  |  | ||||||
| public class Settings extends Appliance { | public class Settings extends Appliance { | ||||||
| @@ -33,6 +35,10 @@ public class Settings extends Appliance { | |||||||
|         ChatMentions, |         ChatMentions, | ||||||
|         DoubleDoors, |         DoubleDoors, | ||||||
|         KnockDoors, |         KnockDoors, | ||||||
|  |         BorderWarning, | ||||||
|  |         LocatorBar, | ||||||
|  |         InfoBars, | ||||||
|  |         CoordinateDisplay | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static Settings instance() { |     public static Settings instance() { | ||||||
| @@ -56,6 +62,16 @@ public class Settings extends Appliance { | |||||||
|  |  | ||||||
|     private final WeakHashMap<Player, OpenSettingsInventory> openSettingsInventories = new WeakHashMap<>(); |     private final WeakHashMap<Player, OpenSettingsInventory> openSettingsInventories = new WeakHashMap<>(); | ||||||
|     private final WeakHashMap<Player, List<Setting<?>>> settingsCache = new WeakHashMap<>(); |     private final WeakHashMap<Player, List<Setting<?>>> settingsCache = new WeakHashMap<>(); | ||||||
|  |     protected final Map<Class<? extends Setting<?>>, Consumer<Player>> changeListeners = new WeakHashMap<>(); | ||||||
|  |  | ||||||
|  |     public <TDataType extends Setting<?>> void addChangeListener(Class<TDataType> setting, Consumer<Player> listener) { | ||||||
|  |         this.changeListeners.merge(setting, listener, Consumer::andThen); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public <TDataType extends Setting<?>> void invokeChangeListener(Player player, Class<TDataType> setting) { | ||||||
|  |         Optional.ofNullable(this.changeListeners.get(setting)) | ||||||
|  |             .ifPresent(listener -> listener.accept(player)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     private List<Setting<?>> getSettings(Player player) { |     private List<Setting<?>> getSettings(Player player) { | ||||||
|         if(this.settingsCache.containsKey(player)) return this.settingsCache.get(player); |         if(this.settingsCache.containsKey(player)) return this.settingsCache.get(player); | ||||||
| @@ -135,6 +151,7 @@ public class Settings extends Appliance { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         player.openInventory(inventory); |         player.openInventory(inventory); | ||||||
|  |         InteractSounds.of(player).open(); | ||||||
|         this.openSettingsInventories.put(player, new OpenSettingsInventory(inventory, settings)); |         this.openSettingsInventories.put(player, new OpenSettingsInventory(inventory, settings)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -142,9 +159,9 @@ public class Settings extends Appliance { | |||||||
|         int countOfUncategorized = (int) settings.stream() |         int countOfUncategorized = (int) settings.stream() | ||||||
|             .filter(setting -> !(setting instanceof CategorizedSetting)) |             .filter(setting -> !(setting instanceof CategorizedSetting)) | ||||||
|             .count(); |             .count(); | ||||||
|         int rowsOfUncategorized = (int) Math.ceil((double) countOfUncategorized / 9); |         int invSizeForUncategorized = (int) Math.ceil((double) countOfUncategorized / 9) * 9; | ||||||
|  |  | ||||||
|         int rowsOfCategorized = Arrays.stream(SettingCategory.values()) |         int invSizeForCategorized = Arrays.stream(SettingCategory.values()) | ||||||
|             .map(settingCategory -> settings.stream() |             .map(settingCategory -> settings.stream() | ||||||
|                 .filter(setting -> setting instanceof CategorizedSetting) |                 .filter(setting -> setting instanceof CategorizedSetting) | ||||||
|                 .map(setting -> (CategorizedSetting) setting) |                 .map(setting -> (CategorizedSetting) setting) | ||||||
| @@ -154,17 +171,18 @@ public class Settings extends Appliance { | |||||||
|             .reduce(Integer::sum) |             .reduce(Integer::sum) | ||||||
|             .orElse(1) * 9; |             .orElse(1) * 9; | ||||||
|  |  | ||||||
|         int rows = rowsOfUncategorized + rowsOfCategorized; |         int invSize = invSizeForUncategorized + invSizeForCategorized; | ||||||
|         if(rows % 9 != 0) throw new IllegalStateException( |         if(invSize % 9 != 0) throw new IllegalStateException( | ||||||
|             String.format("Failed to calculate settings inventory size. %d is not an multiple of 9", rows) |             String.format("Failed to calculate settings inventory size. %d is not an multiple of 9", invSize) | ||||||
|         ); |         ); | ||||||
|         return rows; |         return invSize; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void onSettingsClose(Player player) { |     public void onSettingsClose(Player player) { | ||||||
|         if(!this.openSettingsInventories.containsKey(player)) return; |         if(!this.openSettingsInventories.containsKey(player)) return; | ||||||
|         this.openSettingsInventories.remove(player); |         this.openSettingsInventories.remove(player); | ||||||
|         player.updateInventory(); |         player.updateInventory(); | ||||||
|  |         InteractSounds.of(player).close(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public boolean hasSettingsNotOpen(Player player) { |     public boolean hasSettingsNotOpen(Player player) { | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import org.bukkit.command.Command; | import org.bukkit.command.Command; | ||||||
| import org.bukkit.command.CommandSender; | import org.bukkit.command.CommandSender; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
|   | |||||||
| @@ -0,0 +1,103 @@ | |||||||
|  | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.datatypes; | ||||||
|  |  | ||||||
|  | import com.google.gson.Gson; | ||||||
|  | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings; | ||||||
|  | import net.kyori.adventure.text.Component; | ||||||
|  | import net.kyori.adventure.text.format.NamedTextColor; | ||||||
|  | import org.bukkit.entity.Player; | ||||||
|  | import org.bukkit.event.inventory.ClickType; | ||||||
|  | import org.bukkit.inventory.meta.ItemMeta; | ||||||
|  | import org.bukkit.persistence.PersistentDataContainer; | ||||||
|  | import org.bukkit.persistence.PersistentDataType; | ||||||
|  |  | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Objects; | ||||||
|  | import java.util.stream.IntStream; | ||||||
|  | import java.util.stream.Stream; | ||||||
|  |  | ||||||
|  | public abstract class IntegerSetting extends Setting<Integer> { | ||||||
|  |     private final List<Integer> options; | ||||||
|  |  | ||||||
|  |     public IntegerSetting(Settings.Key key, int minimum, int maximum) { | ||||||
|  |         this(key, IntStream.range(minimum, maximum+1).boxed().toList()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public IntegerSetting(Settings.Key key, List<Integer> options) { | ||||||
|  |         super(key); | ||||||
|  |         this.options = options; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public ItemMeta buildMeta(ItemMeta meta) { | ||||||
|  |         Component componentBefore = Component.text("  " + this.fillWithSpaces(this.options.getLast())); | ||||||
|  |         Component componentAfter = Component.text("  " + this.fillWithSpaces(this.options.getFirst())); | ||||||
|  |         int listIndex = this.options.indexOf(this.state); | ||||||
|  |         if(listIndex > 0) componentBefore = Component.text("  " + this.fillWithSpaces(this.options.get(listIndex-1))); | ||||||
|  |         if(listIndex < this.options.size()-1) componentAfter = Component.text("  " + this.fillWithSpaces(this.options.get(listIndex+1))); | ||||||
|  |  | ||||||
|  |         meta.displayName(Component.text(this.title(), NamedTextColor.WHITE)); | ||||||
|  |         List<Component> lore = new ArrayList<>(Stream.of( | ||||||
|  |             Component.empty() | ||||||
|  |                 .append(Component.text("Wert: ", NamedTextColor.DARK_GRAY)), | ||||||
|  |             Component.empty() | ||||||
|  |                 .append(componentBefore.color(NamedTextColor.DARK_GRAY)) | ||||||
|  |                 .append(Component.text("  " + this.fillWithSpaces(this.state), NamedTextColor.GREEN)) | ||||||
|  |                 .append(componentAfter.color(NamedTextColor.DARK_GRAY)), | ||||||
|  |             Component.empty() | ||||||
|  |         ).toList()); | ||||||
|  |         lore.addAll(this.buildDescription(this.description())); | ||||||
|  |         meta.lore(lore); | ||||||
|  |         return meta; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private String fillWithSpaces(Integer option) { | ||||||
|  |         String optionString = option.toString(); | ||||||
|  |         int optionLength = optionString.length(); | ||||||
|  |         int maxInteger = this.options.stream().mapToInt(value -> value).max().orElse(0); | ||||||
|  |         int maxLength = String.valueOf(maxInteger).length(); | ||||||
|  |         int padding = maxLength - optionLength; | ||||||
|  |  | ||||||
|  |         int padEnd = padding / 2; | ||||||
|  |         int padStart = padding - padEnd; | ||||||
|  |  | ||||||
|  |         optionString = " ".repeat(padStart) + optionString + " ".repeat(padEnd); | ||||||
|  |         return optionString; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     protected void change(Player player, ClickType clickType) { | ||||||
|  |         int elementBefore = this.options.getLast(); | ||||||
|  |         int elementAfter = this.options.getFirst(); | ||||||
|  |         int listIndex = this.options.indexOf(this.state); | ||||||
|  |         if(listIndex > 0) elementBefore = this.options.get(listIndex-1); | ||||||
|  |         if(listIndex < this.options.size()-1) elementAfter = this.options.get(listIndex+1); | ||||||
|  |  | ||||||
|  |         if(clickType.equals(ClickType.LEFT)) this.state = elementBefore; | ||||||
|  |         if(clickType.equals(ClickType.RIGHT)) this.state = elementAfter; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     protected void fromStorage(PersistentDataContainer container) { | ||||||
|  |         this.state = container.has(this.getNamespacedKey()) | ||||||
|  |             ? Integer.valueOf(Objects.requireNonNull(container.get(this.getNamespacedKey(), PersistentDataType.STRING))) | ||||||
|  |             : this.defaultValue(); | ||||||
|  |  | ||||||
|  |         if(!this.options.contains(this.state)) this.state = this.defaultValue(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     protected void toStorage(PersistentDataContainer container, Integer value) { | ||||||
|  |         container.set(this.getNamespacedKey(), PersistentDataType.STRING, new Gson().toJson(value)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Class<?> dataType() { | ||||||
|  |         return Integer.class; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Integer state() { | ||||||
|  |         return this.state; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,8 +1,9 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.datatypes; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.datatypes; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.Main; | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings; | ||||||
| import eu.mhsl.craftattack.core.util.text.ComponentUtil; | import eu.mhsl.craftattack.spawn.core.util.text.ComponentUtil; | ||||||
|  | import eu.mhsl.craftattack.spawn.core.util.world.InteractSounds; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.TextComponent; | import net.kyori.adventure.text.TextComponent; | ||||||
| import net.kyori.adventure.text.format.NamedTextColor; | import net.kyori.adventure.text.format.NamedTextColor; | ||||||
| @@ -17,7 +18,7 @@ import org.bukkit.persistence.PersistentDataContainer; | |||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
| public abstract class Setting<TDataType> { | public abstract class Setting<TDataType> { | ||||||
|     TDataType state; |     protected TDataType state; | ||||||
|     private final Settings.Key key; |     private final Settings.Key key; | ||||||
|  |  | ||||||
|     public Setting(Settings.Key key) { |     public Setting(Settings.Key key) { | ||||||
| @@ -25,7 +26,7 @@ public abstract class Setting<TDataType> { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     public NamespacedKey getNamespacedKey() { |     public NamespacedKey getNamespacedKey() { | ||||||
|         return new NamespacedKey(Main.instance(), this.key.name()); |         return new NamespacedKey(Settings.class.getSimpleName().toLowerCase(), this.key.name().toLowerCase()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public Settings.Key getKey() { |     public Settings.Key getKey() { | ||||||
| @@ -33,12 +34,32 @@ public abstract class Setting<TDataType> { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void initializeFromPlayer(Player p) { |     public void initializeFromPlayer(Player p) { | ||||||
|         this.fromStorage(p.getPersistentDataContainer()); |         PersistentDataContainer dataContainer = p.getPersistentDataContainer(); | ||||||
|  |         try { | ||||||
|  |             this.fromStorage(dataContainer); | ||||||
|  |         } catch(IllegalArgumentException e) { | ||||||
|  |             Main.logger().warning(String.format( | ||||||
|  |                 "Could not load state of setting %s from player %s: '%s'\n Did the datatype of the setting change?", | ||||||
|  |                 this.getNamespacedKey(), | ||||||
|  |                 e.getMessage(), | ||||||
|  |                 p.getName() | ||||||
|  |             )); | ||||||
|  |             dataContainer.remove(this.getNamespacedKey()); | ||||||
|  |             this.fromStorage(dataContainer); | ||||||
|  |             Main.logger().info(String.format( | ||||||
|  |                 "Restoring defaults of setting %s of player %s", | ||||||
|  |                 this.getNamespacedKey(), | ||||||
|  |                 p.getName() | ||||||
|  |             )); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void triggerChange(Player p, ClickType clickType) { |     public void triggerChange(Player p, ClickType clickType) { | ||||||
|  |         if(clickType.equals(ClickType.DOUBLE_CLICK)) return; | ||||||
|         this.change(p, clickType); |         this.change(p, clickType); | ||||||
|  |         InteractSounds.of(p).click(); | ||||||
|         this.toStorage(p.getPersistentDataContainer(), this.state()); |         this.toStorage(p.getPersistentDataContainer(), this.state()); | ||||||
|  |         Settings.instance().invokeChangeListener(p, this.getClass()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public ItemStack buildItem() { |     public ItemStack buildItem() { | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.listeners; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.listeners; | ||||||
|  |  | ||||||
| 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 eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings; | ||||||
| import org.bukkit.event.EventHandler; | import org.bukkit.event.EventHandler; | ||||||
| import org.bukkit.event.player.PlayerSwapHandItemsEvent; | import org.bukkit.event.player.PlayerSwapHandItemsEvent; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.listeners; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.listeners; | ||||||
|  |  | ||||||
| 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 eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings; | ||||||
| import org.bukkit.entity.Player; | import org.bukkit.entity.Player; | ||||||
| import org.bukkit.event.EventHandler; | import org.bukkit.event.EventHandler; | ||||||
|   | |||||||
| @@ -1,13 +1,13 @@ | |||||||
| package eu.mhsl.craftattack.spawn.craftattack.appliances.metaGameplay.tablist; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.tablist; | ||||||
| 
 | 
 | ||||||
| import eu.mhsl.craftattack.core.Main; | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
| import eu.mhsl.craftattack.core.appliance.Appliance; | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
| import eu.mhsl.craftattack.spawn.craftattack.appliances.metaGameplay.report.Report; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.report.Report; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings; | ||||||
| import eu.mhsl.craftattack.core.util.IteratorUtil; | import eu.mhsl.craftattack.spawn.core.util.IteratorUtil; | ||||||
| import eu.mhsl.craftattack.core.util.statistics.NetworkMonitor; | import eu.mhsl.craftattack.spawn.core.util.statistics.NetworkMonitor; | ||||||
| import eu.mhsl.craftattack.core.util.text.ComponentUtil; | import eu.mhsl.craftattack.spawn.core.util.text.ComponentUtil; | ||||||
| import eu.mhsl.craftattack.core.util.text.RainbowComponent; | import eu.mhsl.craftattack.spawn.core.util.text.RainbowComponent; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.format.NamedTextColor; | import net.kyori.adventure.text.format.NamedTextColor; | ||||||
| import net.kyori.adventure.util.Ticks; | import net.kyori.adventure.util.Ticks; | ||||||
| @@ -23,7 +23,8 @@ import java.util.List; | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| public class Tablist extends Appliance { | public class Tablist extends Appliance { | ||||||
|     private final RainbowComponent serverName = new RainbowComponent(" CraftAttack 7 ", 7, 3); |     private final String projectTitle = this.localConfig().getString("projectTitle", "Title not configured"); | ||||||
|  |     private final RainbowComponent serverName = new RainbowComponent(String.format(" %s ", this.projectTitle), 7, 3); | ||||||
|     private NetworkMonitor networkMonitor; |     private NetworkMonitor networkMonitor; | ||||||
|     private OperatingSystemMXBean systemMonitor; |     private OperatingSystemMXBean systemMonitor; | ||||||
| 
 | 
 | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.craftattack.appliances.metaGameplay.tablist; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.tablist; | ||||||
| 
 | 
 | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceListener; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; | ||||||
| import org.bukkit.event.EventHandler; | import org.bukkit.event.EventHandler; | ||||||
| import org.bukkit.event.player.PlayerJoinEvent; | import org.bukkit.event.player.PlayerJoinEvent; | ||||||
| 
 | 
 | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| package eu.mhsl.craftattack.spawn.craftattack.appliances.metaGameplay.tablist; | package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.tablist; | ||||||
| 
 | 
 | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.CategorizedSetting; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.CategorizedSetting; | ||||||
| import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.SettingCategory; | import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.SettingCategory; | ||||||
| @@ -0,0 +1,62 @@ | |||||||
|  | package eu.mhsl.craftattack.spawn.common.appliances.security.antiAutoTotem; | ||||||
|  |  | ||||||
|  | import eu.mhsl.craftattack.spawn.common.appliances.tooling.acInform.AcInform; | ||||||
|  | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
|  | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
|  | import org.bukkit.Bukkit; | ||||||
|  | import org.bukkit.Material; | ||||||
|  | import org.bukkit.entity.Player; | ||||||
|  | import org.bukkit.event.Listener; | ||||||
|  | import org.bukkit.inventory.PlayerInventory; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.concurrent.atomic.AtomicInteger; | ||||||
|  | import java.util.function.Function; | ||||||
|  | import java.util.function.Supplier; | ||||||
|  |  | ||||||
|  | public class AntiAutoTotem extends Appliance { | ||||||
|  |  | ||||||
|  |     public void checkTotemUse(Player player) { | ||||||
|  |         PlayerInventory playerInv = player.getInventory(); | ||||||
|  |  | ||||||
|  |         Supplier<List<Material>> getHeldItems = () -> List.of( | ||||||
|  |             playerInv.getItemInMainHand().getType(), | ||||||
|  |             playerInv.getItemInOffHand().getType() | ||||||
|  |         ); | ||||||
|  |         Function<Player, Boolean> isCurrentlyHoldingTotem = (p) -> getHeldItems.get().contains(Material.TOTEM_OF_UNDYING); | ||||||
|  |  | ||||||
|  |         if(!isCurrentlyHoldingTotem.apply(player)) return; | ||||||
|  |         if(getHeldItems.get().stream().allMatch(material -> material.equals(Material.TOTEM_OF_UNDYING))) return; | ||||||
|  |  | ||||||
|  |         AtomicInteger tickCounter = new AtomicInteger(); | ||||||
|  |         Bukkit.getScheduler().runTaskTimer( | ||||||
|  |             Main.instance(), | ||||||
|  |             (task) -> { | ||||||
|  |                 if(tickCounter.incrementAndGet() > 10) { | ||||||
|  |                     task.cancel(); | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 if(isCurrentlyHoldingTotem.apply(player)) { | ||||||
|  |                     task.cancel(); | ||||||
|  |                     Main.instance().getAppliance(AcInform.class).notifyAdmins( | ||||||
|  |                         "internal", | ||||||
|  |                         player.getName(), | ||||||
|  |                         "antiAutoTotem", | ||||||
|  |                         (float) tickCounter.get() | ||||||
|  |                     ); | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             1, | ||||||
|  |             1 | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     protected @NotNull List<Listener> listeners() { | ||||||
|  |         return List.of( | ||||||
|  |             new OnTotemUseListener() | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,15 @@ | |||||||
|  | package eu.mhsl.craftattack.spawn.common.appliances.security.antiAutoTotem; | ||||||
|  |  | ||||||
|  | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; | ||||||
|  | import org.bukkit.entity.Player; | ||||||
|  | import org.bukkit.event.EventHandler; | ||||||
|  | import org.bukkit.event.entity.EntityResurrectEvent; | ||||||
|  |  | ||||||
|  | class OnTotemUseListener extends ApplianceListener<AntiAutoTotem> { | ||||||
|  |     @EventHandler | ||||||
|  |     public void onTotem(EntityResurrectEvent event) { | ||||||
|  |         if(event.isCancelled()) return; | ||||||
|  |         if(!(event.getEntity() instanceof Player player)) return; | ||||||
|  |         this.getAppliance().checkTotemUse(player); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,66 @@ | |||||||
|  | package eu.mhsl.craftattack.spawn.common.appliances.security.antiFormattedBook; | ||||||
|  |  | ||||||
|  | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
|  | import net.kyori.adventure.text.*; | ||||||
|  | import net.kyori.adventure.text.format.Style; | ||||||
|  | import net.kyori.adventure.text.format.TextColor; | ||||||
|  | import net.kyori.adventure.text.format.TextDecoration; | ||||||
|  | import org.bukkit.event.Listener; | ||||||
|  | import org.bukkit.inventory.meta.BookMeta; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  | import org.jetbrains.annotations.Nullable; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Objects; | ||||||
|  |  | ||||||
|  | public class AntiFormattedBook extends Appliance { | ||||||
|  |     private static final char SECTION = '\u00A7'; | ||||||
|  |  | ||||||
|  |     public boolean containsFormatting(BookMeta meta) { | ||||||
|  |         if (this.hasFormattingDeep(meta.title())) return true; | ||||||
|  |         if (this.hasFormattingDeep(meta.author())) return true; | ||||||
|  |  | ||||||
|  |         for (Component c : meta.pages()) { | ||||||
|  |             if (this.hasFormattingDeep(c)) return true; | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private boolean hasFormattingDeep(@Nullable Component component) { | ||||||
|  |         if(component == null) return false; | ||||||
|  |         if (this.hastFormatting(component)) return true; | ||||||
|  |  | ||||||
|  |         if (component instanceof TextComponent tc && tc.content().indexOf(SECTION) >= 0) return true; | ||||||
|  |  | ||||||
|  |         if (component instanceof NBTComponent<?, ?> nbt) { | ||||||
|  |             if (nbt.separator() != null && this.hasFormattingDeep(nbt.separator())) return true; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         for (Component child : component.children()) { | ||||||
|  |             if (this.hasFormattingDeep(child)) return true; | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private boolean hastFormatting(Component component) { | ||||||
|  |         Style style = component.style(); | ||||||
|  |  | ||||||
|  |         TextColor color = style.color(); | ||||||
|  |         if (color != null) return true; | ||||||
|  |         if (style.font() != null) return true; | ||||||
|  |         if (style.insertion() != null && !Objects.requireNonNull(style.insertion()).isEmpty()) return true; | ||||||
|  |  | ||||||
|  |         for (var decoration : style.decorations().entrySet()) { | ||||||
|  |             if (decoration.getValue() == TextDecoration.State.TRUE) return true; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return style.hoverEvent() != null || style.clickEvent() != null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     protected @NotNull List<Listener> listeners() { | ||||||
|  |         return List.of( | ||||||
|  |             new BookEditListener() | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,36 @@ | |||||||
|  | package eu.mhsl.craftattack.spawn.common.appliances.security.antiFormattedBook; | ||||||
|  |  | ||||||
|  | import eu.mhsl.craftattack.spawn.common.appliances.tooling.acInform.AcInform; | ||||||
|  | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
|  | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; | ||||||
|  | import net.kyori.adventure.text.Component; | ||||||
|  | import org.bukkit.entity.Player; | ||||||
|  | import org.bukkit.event.EventHandler; | ||||||
|  | import org.bukkit.event.player.PlayerEditBookEvent; | ||||||
|  | import org.bukkit.inventory.meta.BookMeta; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | class BookEditListener extends ApplianceListener<AntiFormattedBook> { | ||||||
|  |     @EventHandler | ||||||
|  |     public void onBookEdit(PlayerEditBookEvent event) { | ||||||
|  |         Player player = event.getPlayer(); | ||||||
|  |         BookMeta meta = event.getNewBookMeta(); | ||||||
|  |  | ||||||
|  |         if (this.getAppliance().containsFormatting(meta)) { | ||||||
|  |             Main.instance().getAppliance(AcInform.class).notifyAdmins( | ||||||
|  |                 "internal", | ||||||
|  |                 player.getName(), | ||||||
|  |                 "illegalBookFormatting", | ||||||
|  |                 1f | ||||||
|  |             ); | ||||||
|  |  | ||||||
|  |             BookMeta sanitized = meta.clone(); | ||||||
|  |             sanitized.title(null); | ||||||
|  |             sanitized.author(null); | ||||||
|  |             //noinspection ResultOfMethodCallIgnored | ||||||
|  |             sanitized.pages(List.of(Component.empty())); | ||||||
|  |             event.setNewBookMeta(sanitized); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,78 @@ | |||||||
|  | package eu.mhsl.craftattack.spawn.common.appliances.security.antiIllegalBundlePicker; | ||||||
|  |  | ||||||
|  | import eu.mhsl.craftattack.spawn.common.appliances.tooling.acInform.AcInform; | ||||||
|  | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
|  | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
|  | import org.bukkit.Bukkit; | ||||||
|  | import org.bukkit.Material; | ||||||
|  | import org.bukkit.entity.Player; | ||||||
|  | import org.bukkit.event.Listener; | ||||||
|  | import org.bukkit.event.inventory.InventoryClickEvent; | ||||||
|  | import org.bukkit.inventory.InventoryView; | ||||||
|  | import org.bukkit.inventory.ItemStack; | ||||||
|  | import org.bukkit.inventory.meta.BundleMeta; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  |  | ||||||
|  | import java.util.*; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  |  | ||||||
|  | public class AntiIllegalBundlePicker extends Appliance { | ||||||
|  |     private static final int visibleSlotsInBundle = 9; | ||||||
|  |  | ||||||
|  |     public void trackBundle(InventoryClickEvent event) { | ||||||
|  |         ItemStack bundle = Objects.requireNonNull(event.getCurrentItem()); | ||||||
|  |         final int rawSlot = event.getRawSlot(); | ||||||
|  |         final Player player = (Player) event.getWhoClicked(); | ||||||
|  |         final InventoryView view = event.getView(); | ||||||
|  |         final List<ItemStack> before = this.getBundleContents(bundle); | ||||||
|  |  | ||||||
|  |         Bukkit.getScheduler().runTask(Main.instance(), () -> { | ||||||
|  |             ItemStack afterStack = view.getItem(rawSlot); | ||||||
|  |             if(afterStack == null || afterStack.getType() != Material.BUNDLE) return; | ||||||
|  |  | ||||||
|  |             List<ItemStack> after = this.getBundleContents(afterStack); | ||||||
|  |             int removedSlotIndex = this.findRemoved(before, after); | ||||||
|  |  | ||||||
|  |             if(removedSlotIndex >= visibleSlotsInBundle) { | ||||||
|  |                 Main.instance().getAppliance(AcInform.class).notifyAdmins( | ||||||
|  |                     "internal", | ||||||
|  |                     player.getName(), | ||||||
|  |                     "illegalBundlePick", | ||||||
|  |                     (float) removedSlotIndex | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private int findRemoved(@NotNull List<ItemStack> before, @NotNull List<ItemStack> after) { | ||||||
|  |         for (int i = 0; i < Math.max(before.size(), after.size()); i++) { | ||||||
|  |             ItemStack a = i < after.size() ? after.get(i) : null; | ||||||
|  |             ItemStack b = i < before.size() ? before.get(i) : null; | ||||||
|  |  | ||||||
|  |             if (b == null && a == null) continue; | ||||||
|  |             if (b == null) throw new IllegalStateException("Size of bundle was smaller before pickup Action"); | ||||||
|  |  | ||||||
|  |             if (a == null) return i; | ||||||
|  |             if (!a.isSimilar(b)) return i; | ||||||
|  |             if (a.getAmount() != b.getAmount()) return i; | ||||||
|  |         } | ||||||
|  |         throw new IllegalStateException("Failed to find picked Item in bundle"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private List<ItemStack> getBundleContents(@NotNull ItemStack bundle) { | ||||||
|  |         if (bundle.getType() != Material.BUNDLE) | ||||||
|  |             throw new IllegalStateException("ItemStack is not a bundle"); | ||||||
|  |  | ||||||
|  |         BundleMeta meta = (BundleMeta) bundle.getItemMeta(); | ||||||
|  |         return meta.getItems().stream() | ||||||
|  |             .map(ItemStack::clone) | ||||||
|  |             .collect(Collectors.toCollection(ArrayList::new)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     protected @NotNull List<Listener> listeners() { | ||||||
|  |         return List.of( | ||||||
|  |             new OnBundlePickListener() | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,18 @@ | |||||||
|  | package eu.mhsl.craftattack.spawn.common.appliances.security.antiIllegalBundlePicker; | ||||||
|  |  | ||||||
|  | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; | ||||||
|  | import org.bukkit.Material; | ||||||
|  | import org.bukkit.event.EventHandler; | ||||||
|  | import org.bukkit.event.inventory.InventoryAction; | ||||||
|  | import org.bukkit.event.inventory.InventoryClickEvent; | ||||||
|  | import org.bukkit.inventory.ItemStack; | ||||||
|  |  | ||||||
|  | class OnBundlePickListener extends ApplianceListener<AntiIllegalBundlePicker> { | ||||||
|  |     @EventHandler | ||||||
|  |     public void onBundlePick(InventoryClickEvent event) { | ||||||
|  |         if(!event.getAction().equals(InventoryAction.PICKUP_FROM_BUNDLE)) return; | ||||||
|  |         final ItemStack bundle = event.getCurrentItem(); | ||||||
|  |         if (bundle == null || bundle.getType() != Material.BUNDLE) return; | ||||||
|  |         this.getAppliance().trackBundle(event); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,7 +1,7 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.tooling.acInform; | package eu.mhsl.craftattack.spawn.common.appliances.tooling.acInform; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.Appliance; | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.ComponentBuilder; | import net.kyori.adventure.text.ComponentBuilder; | ||||||
| import net.kyori.adventure.text.TextComponent; | import net.kyori.adventure.text.TextComponent; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.tooling.acInform; | package eu.mhsl.craftattack.spawn.common.appliances.tooling.acInform; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import org.bukkit.command.Command; | import org.bukkit.command.Command; | ||||||
| import org.bukkit.command.CommandSender; | import org.bukkit.command.CommandSender; | ||||||
| import org.bukkit.entity.Player; | import org.bukkit.entity.Player; | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.tooling.adminChat; | package eu.mhsl.craftattack.spawn.common.appliances.tooling.adminChat; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.Appliance; | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.event.ClickEvent; | import net.kyori.adventure.text.event.ClickEvent; | ||||||
| import net.kyori.adventure.text.format.NamedTextColor; | import net.kyori.adventure.text.format.NamedTextColor; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.tooling.adminChat; | package eu.mhsl.craftattack.spawn.common.appliances.tooling.adminChat; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import org.bukkit.command.Command; | import org.bukkit.command.Command; | ||||||
| import org.bukkit.command.CommandSender; | import org.bukkit.command.CommandSender; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.tooling.chatMute; | package eu.mhsl.craftattack.spawn.common.appliances.tooling.chatMute; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.Appliance; | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import org.bukkit.NamespacedKey; | import org.bukkit.NamespacedKey; | ||||||
| import org.bukkit.entity.Player; | import org.bukkit.entity.Player; | ||||||
| import org.bukkit.event.Listener; | import org.bukkit.event.Listener; | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.tooling.chatMute; | package eu.mhsl.craftattack.spawn.common.appliances.tooling.chatMute; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceListener; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; | ||||||
| import eu.mhsl.craftattack.core.util.text.DataSizeConverter; | import eu.mhsl.craftattack.spawn.core.util.text.DataSizeConverter; | ||||||
| import io.papermc.paper.event.player.AsyncChatEvent; | import io.papermc.paper.event.player.AsyncChatEvent; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.format.NamedTextColor; | import net.kyori.adventure.text.format.NamedTextColor; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.tooling.chatMute; | package eu.mhsl.craftattack.spawn.common.appliances.tooling.chatMute; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
| import org.bukkit.command.Command; | import org.bukkit.command.Command; | ||||||
| import org.bukkit.command.CommandSender; | import org.bukkit.command.CommandSender; | ||||||
|   | |||||||
| @@ -1,35 +1,59 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.tooling.endPrevent; | package eu.mhsl.craftattack.spawn.common.appliances.tooling.endPrevent; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.Appliance; | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import eu.mhsl.craftattack.core.config.Configuration; | import eu.mhsl.craftattack.spawn.core.config.Configuration; | ||||||
|  | import org.bukkit.Bukkit; | ||||||
|  | import org.bukkit.World; | ||||||
| import org.bukkit.event.Listener; | import org.bukkit.event.Listener; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
|  |  | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
| public class EndPrevent extends Appliance { | public class EndPrevent extends Appliance { | ||||||
|     private final String endDisabledKey = "endDisabled"; |     private final String endPreventKey = "endPrevent"; | ||||||
|     private boolean endDisabled; |     private State endPreventState; | ||||||
|  |     private final World endWorld = Bukkit.getWorlds().stream().filter(world -> world.getEnvironment().equals(World.Environment.THE_END)).findFirst().orElseThrow(); | ||||||
|  |  | ||||||
|  |     public enum State { | ||||||
|  |         OPEN, | ||||||
|  |         CLOSED, | ||||||
|  |         NO_OUTER | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public EndPrevent() { |     public EndPrevent() { | ||||||
|         super("endPrevent"); |         super("endPrevent"); | ||||||
|         this.endDisabled = this.localConfig().getBoolean(this.endDisabledKey); |         this.endPreventState = State.valueOf(this.localConfig().getString(this.endPreventKey, State.OPEN.name())); | ||||||
|  |         this.updateEndBorder(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void setEndDisabled(boolean disabled) { |     private void updateEndBorder() { | ||||||
|         this.localConfig().set(this.endDisabledKey, disabled); |         if(this.endPreventState == State.NO_OUTER) this.endWorld.getWorldBorder().setSize(500); | ||||||
|  |         if(this.endPreventState == State.OPEN) this.endWorld.getWorldBorder().setSize(this.endWorld.getWorldBorder().getMaxSize()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void setEndState(State state) { | ||||||
|  |         this.localConfig().set(this.endPreventKey, state.name()); | ||||||
|         Configuration.saveChanges(); |         Configuration.saveChanges(); | ||||||
|         this.endDisabled = disabled; |         this.endPreventState = state; | ||||||
|  |         this.updateEndBorder(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public boolean isEndDisabled() { |     public boolean isEndClosed() { | ||||||
|         return this.endDisabled; |         return this.endPreventState.equals(State.CLOSED); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public boolean isOnlyInner() { | ||||||
|  |         return this.endPreventState.equals(State.NO_OUTER); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public State getEndPreventState() { | ||||||
|  |         return this.endPreventState; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected @NotNull List<Listener> listeners() { |     protected @NotNull List<Listener> listeners() { | ||||||
|         return List.of(new PreventEnderEyeUseListener()); |         return List.of(new EndPreventListener()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.tooling.endPrevent; | package eu.mhsl.craftattack.spawn.common.appliances.tooling.endPrevent; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.format.NamedTextColor; | import net.kyori.adventure.text.format.NamedTextColor; | ||||||
| import org.bukkit.command.Command; | import org.bukkit.command.Command; | ||||||
| @@ -12,7 +12,11 @@ import java.util.List; | |||||||
| import java.util.Map; | import java.util.Map; | ||||||
|  |  | ||||||
| class EndPreventCommand extends ApplianceCommand<EndPrevent> { | class EndPreventCommand extends ApplianceCommand<EndPrevent> { | ||||||
|     private final Map<String, Boolean> arguments = Map.of("preventEnd", true, "allowEnd", false); |     private final Map<String, EndPrevent.State> arguments = Map.of( | ||||||
|  |         "preventEnd", EndPrevent.State.CLOSED, | ||||||
|  |         "allowEnd", EndPrevent.State.OPEN, | ||||||
|  |         "onlyInnerEnd", EndPrevent.State.NO_OUTER | ||||||
|  |     ); | ||||||
|  |  | ||||||
|     public EndPreventCommand() { |     public EndPreventCommand() { | ||||||
|         super("endPrevent"); |         super("endPrevent"); | ||||||
| @@ -21,11 +25,11 @@ class EndPreventCommand extends ApplianceCommand<EndPrevent> { | |||||||
|     @Override |     @Override | ||||||
|     protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception { |     protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception { | ||||||
|         if(args.length == 1 && this.arguments.containsKey(args[0])) { |         if(args.length == 1 && this.arguments.containsKey(args[0])) { | ||||||
|             this.getAppliance().setEndDisabled(this.arguments.get(args[0])); |             this.getAppliance().setEndState(this.arguments.get(args[0])); | ||||||
|             sender.sendMessage(Component.text("Setting updated!", NamedTextColor.GREEN)); |             sender.sendMessage(Component.text("Setting updated!", NamedTextColor.GREEN)); | ||||||
|         } |         } | ||||||
|         sender.sendMessage(Component.text( |         sender.sendMessage(Component.text( | ||||||
|             String.format("The End is %s!", this.getAppliance().isEndDisabled() ? "closed" : "open"), |             String.format("The End is now on '%s'!", this.getAppliance().getEndPreventState().name()), | ||||||
|             NamedTextColor.GOLD |             NamedTextColor.GOLD | ||||||
|         )); |         )); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -0,0 +1,49 @@ | |||||||
|  | package eu.mhsl.craftattack.spawn.common.appliances.tooling.endPrevent; | ||||||
|  |  | ||||||
|  | import com.destroystokyo.paper.event.player.PlayerTeleportEndGatewayEvent; | ||||||
|  | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; | ||||||
|  | import net.kyori.adventure.text.Component; | ||||||
|  | import net.kyori.adventure.text.format.NamedTextColor; | ||||||
|  | import org.bukkit.Material; | ||||||
|  | import org.bukkit.World; | ||||||
|  | import org.bukkit.entity.Player; | ||||||
|  | import org.bukkit.event.Cancellable; | ||||||
|  | import org.bukkit.event.EventHandler; | ||||||
|  | import org.bukkit.event.player.PlayerInteractEvent; | ||||||
|  | import org.bukkit.event.player.PlayerPortalEvent; | ||||||
|  |  | ||||||
|  | class EndPreventListener 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; | ||||||
|  |  | ||||||
|  |         this.cancelIfClosed(event, event.getPlayer()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @EventHandler | ||||||
|  |     public void onPlayerPortal(PlayerPortalEvent event) { | ||||||
|  |         if(!event.getTo().getWorld().getEnvironment().equals(World.Environment.THE_END)) return; | ||||||
|  |  | ||||||
|  |         this.cancelIfClosed(event, event.getPlayer()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @EventHandler | ||||||
|  |     public void onPlayerEndGateway(PlayerTeleportEndGatewayEvent event) { | ||||||
|  |         this.cancelIfOnlyInner(event, event.getPlayer()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void cancelIfClosed(Cancellable event, Player p) { | ||||||
|  |         if(!this.getAppliance().isEndClosed()) return; | ||||||
|  |         event.setCancelled(true); | ||||||
|  |         p.sendActionBar(Component.text("Das End ist nicht freigeschaltet!", NamedTextColor.RED)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void cancelIfOnlyInner(Cancellable event, Player p) { | ||||||
|  |         if(!this.getAppliance().isOnlyInner()) return; | ||||||
|  |         event.setCancelled(true); | ||||||
|  |         p.sendActionBar(Component.text("Das Outer End ist nicht freigeschaltet!", NamedTextColor.RED)); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,23 +0,0 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.tooling.endPrevent; |  | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.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; |  | ||||||
|  |  | ||||||
| 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(!this.getAppliance().isEndDisabled()) return; |  | ||||||
|  |  | ||||||
|         event.setCancelled(true); |  | ||||||
|         event.getPlayer().sendActionBar(Component.text("Das End ist noch nicht freigeschaltet!", NamedTextColor.RED)); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,8 +1,8 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.tooling.kick; | package eu.mhsl.craftattack.spawn.common.appliances.tooling.kick; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.Appliance; | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import eu.mhsl.craftattack.core.util.text.DisconnectInfo; | import eu.mhsl.craftattack.spawn.core.util.text.DisconnectInfo; | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
| import org.bukkit.entity.Player; | import org.bukkit.entity.Player; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.tooling.kick; | package eu.mhsl.craftattack.spawn.common.appliances.tooling.kick; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
| import org.bukkit.command.Command; | import org.bukkit.command.Command; | ||||||
| import org.bukkit.command.CommandSender; | import org.bukkit.command.CommandSender; | ||||||
| @@ -19,6 +19,7 @@ class KickCommand extends ApplianceCommand<Kick> { | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception { |     protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception { | ||||||
|  |         if(args.length < 1) throw new Error("Es muss ein Spielername angegeben werden!"); | ||||||
|         this.getAppliance().kick( |         this.getAppliance().kick( | ||||||
|             args[0], |             args[0], | ||||||
|             Arrays.stream(args).skip(1).collect(Collectors.joining(" ")) |             Arrays.stream(args).skip(1).collect(Collectors.joining(" ")) | ||||||
|   | |||||||
| @@ -1,8 +1,8 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.tooling.maintenance; | package eu.mhsl.craftattack.spawn.common.appliances.tooling.maintenance; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.Appliance; | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import eu.mhsl.craftattack.core.config.Configuration; | import eu.mhsl.craftattack.spawn.core.config.Configuration; | ||||||
| import org.bukkit.event.Listener; | import org.bukkit.event.Listener; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.tooling.maintenance; | package eu.mhsl.craftattack.spawn.common.appliances.tooling.maintenance; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.format.NamedTextColor; | import net.kyori.adventure.text.format.NamedTextColor; | ||||||
| import org.bukkit.command.Command; | import org.bukkit.command.Command; | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.tooling.maintenance; | package eu.mhsl.craftattack.spawn.common.appliances.tooling.maintenance; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceListener; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; | ||||||
| import eu.mhsl.craftattack.core.util.text.DisconnectInfo; | import eu.mhsl.craftattack.spawn.core.util.text.DisconnectInfo; | ||||||
| import org.bukkit.event.EventHandler; | import org.bukkit.event.EventHandler; | ||||||
| import org.bukkit.event.player.PlayerLoginEvent; | import org.bukkit.event.player.PlayerLoginEvent; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,8 +1,8 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.tooling.panicBan; | package eu.mhsl.craftattack.spawn.common.appliances.tooling.panicBan; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.Appliance; | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import eu.mhsl.craftattack.core.util.text.DisconnectInfo; | import eu.mhsl.craftattack.spawn.core.util.text.DisconnectInfo; | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
| import org.bukkit.entity.Player; | import org.bukkit.entity.Player; | ||||||
| import org.bukkit.event.Listener; | import org.bukkit.event.Listener; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.tooling.panicBan; | package eu.mhsl.craftattack.spawn.common.appliances.tooling.panicBan; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
| import org.bukkit.OfflinePlayer; | import org.bukkit.OfflinePlayer; | ||||||
| import org.bukkit.command.Command; | import org.bukkit.command.Command; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.tooling.panicBan; | package eu.mhsl.craftattack.spawn.common.appliances.tooling.panicBan; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceListener; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; | ||||||
| import org.bukkit.event.EventHandler; | import org.bukkit.event.EventHandler; | ||||||
| import org.bukkit.event.player.AsyncPlayerPreLoginEvent; | import org.bukkit.event.player.AsyncPlayerPreLoginEvent; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,8 +1,8 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.tooling.playerlimit; | package eu.mhsl.craftattack.spawn.common.appliances.tooling.playerlimit; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.Appliance; | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import eu.mhsl.craftattack.core.config.Configuration; | import eu.mhsl.craftattack.spawn.core.config.Configuration; | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
| import org.bukkit.event.Listener; | import org.bukkit.event.Listener; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.tooling.playerlimit; | package eu.mhsl.craftattack.spawn.common.appliances.tooling.playerlimit; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceListener; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; | ||||||
| import eu.mhsl.craftattack.core.util.text.DisconnectInfo; | import eu.mhsl.craftattack.spawn.core.util.text.DisconnectInfo; | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
| import org.bukkit.event.EventHandler; | import org.bukkit.event.EventHandler; | ||||||
| import org.bukkit.event.player.AsyncPlayerPreLoginEvent; | import org.bukkit.event.player.AsyncPlayerPreLoginEvent; | ||||||
| @@ -9,6 +9,7 @@ import org.bukkit.event.player.AsyncPlayerPreLoginEvent; | |||||||
| class PlayerLimiterListener extends ApplianceListener<PlayerLimit> { | class PlayerLimiterListener extends ApplianceListener<PlayerLimit> { | ||||||
|     @EventHandler |     @EventHandler | ||||||
|     public void onLogin(AsyncPlayerPreLoginEvent playerPreLoginEvent) { |     public void onLogin(AsyncPlayerPreLoginEvent playerPreLoginEvent) { | ||||||
|  |         if(Bukkit.getOnlinePlayers().size() >= this.getAppliance().getLimit()) { | ||||||
|             playerPreLoginEvent.kickMessage( |             playerPreLoginEvent.kickMessage( | ||||||
|                 new DisconnectInfo( |                 new DisconnectInfo( | ||||||
|                     "Hohe Serverauslastung", |                     "Hohe Serverauslastung", | ||||||
| @@ -17,8 +18,7 @@ class PlayerLimiterListener extends ApplianceListener<PlayerLimit> { | |||||||
|                     playerPreLoginEvent.getUniqueId() |                     playerPreLoginEvent.getUniqueId() | ||||||
|                 ).getComponent() |                 ).getComponent() | ||||||
|             ); |             ); | ||||||
|  |  | ||||||
|         if(Bukkit.getOnlinePlayers().size() >= this.getAppliance().getLimit()) |  | ||||||
|             playerPreLoginEvent.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_FULL); |             playerPreLoginEvent.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_FULL); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | } | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.tooling.playerlimit; | package eu.mhsl.craftattack.spawn.common.appliances.tooling.playerlimit; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.format.NamedTextColor; | import net.kyori.adventure.text.format.NamedTextColor; | ||||||
| import org.bukkit.command.Command; | import org.bukkit.command.Command; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.tooling.restart; | package eu.mhsl.craftattack.spawn.common.appliances.tooling.restart; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import org.bukkit.command.Command; | import org.bukkit.command.Command; | ||||||
| import org.bukkit.command.CommandSender; | import org.bukkit.command.CommandSender; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
|   | |||||||
| @@ -1,9 +1,9 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.tooling.restart; | package eu.mhsl.craftattack.spawn.common.appliances.tooling.restart; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.Appliance; | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import eu.mhsl.craftattack.core.util.IteratorUtil; | import eu.mhsl.craftattack.spawn.core.util.IteratorUtil; | ||||||
| import eu.mhsl.craftattack.core.util.text.Countdown; | import eu.mhsl.craftattack.spawn.core.util.text.Countdown; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.format.NamedTextColor; | import net.kyori.adventure.text.format.NamedTextColor; | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.spawn.common.appliances.tooling.restart; | package eu.mhsl.craftattack.spawn.common.appliances.tooling.restart; | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.appliance.ApplianceCommand; | import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; | ||||||
| import org.bukkit.command.Command; | import org.bukkit.command.Command; | ||||||
| import org.bukkit.command.CommandSender; | import org.bukkit.command.CommandSender; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| dependencies { | dependencies { | ||||||
|     compileOnly 'io.papermc.paper:paper-api:1.21.1-R0.1-SNAPSHOT' |     compileOnly 'io.papermc.paper:paper-api:1.21.8-R0.1-SNAPSHOT' | ||||||
|     compileOnly 'org.geysermc.floodgate:api:2.2.2-SNAPSHOT' |     compileOnly 'org.geysermc.floodgate:api:2.2.4-SNAPSHOT' | ||||||
|     implementation 'org.apache.httpcomponents:httpclient:4.5.14' |     implementation 'org.apache.httpcomponents:httpclient:4.5.14' | ||||||
|     implementation 'com.sparkjava:spark-core:2.9.4' |     implementation 'com.sparkjava:spark-core:2.9.4' | ||||||
|     implementation 'org.reflections:reflections:0.10.2' |     implementation 'org.reflections:reflections:0.10.2' | ||||||
|   | |||||||
| @@ -1,4 +0,0 @@ | |||||||
| package eu.mhsl.craftattack.core.api.client; |  | ||||||
|  |  | ||||||
| public record ReqResp<TData>(int status, TData data) { |  | ||||||
| } |  | ||||||
| @@ -1,27 +0,0 @@ | |||||||
| package eu.mhsl.craftattack.core.api.client.repositories; |  | ||||||
|  |  | ||||||
| import com.google.common.reflect.TypeToken; |  | ||||||
| import eu.mhsl.craftattack.core.api.client.HttpRepository; |  | ||||||
| import eu.mhsl.craftattack.core.api.client.ReqResp; |  | ||||||
| import eu.mhsl.craftattack.core.util.api.WebsiteApiUtil; |  | ||||||
|  |  | ||||||
| import java.lang.reflect.Type; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Map; |  | ||||||
| import java.util.UUID; |  | ||||||
|  |  | ||||||
| public class FeedbackRepository extends HttpRepository { |  | ||||||
|     public FeedbackRepository() { |  | ||||||
|         super(WebsiteApiUtil.getBaseUri(), WebsiteApiUtil::withAuthorizationSecret); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public record Request(String event, List<UUID> users) { |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public ReqResp<Map<UUID, String>> createFeedbackUrls(Request data) { |  | ||||||
|         final Type responseType = new TypeToken<Map<UUID, String>>() { |  | ||||||
|         }.getType(); |  | ||||||
|         ReqResp<Object> rawData = this.post("feedback", data, Object.class); |  | ||||||
|         return new ReqResp<>(rawData.status(), this.gson.fromJson(this.gson.toJson(rawData.data()), responseType)); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,57 +0,0 @@ | |||||||
| package eu.mhsl.craftattack.core.api.client.repositories; |  | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.api.client.HttpRepository; |  | ||||||
| import eu.mhsl.craftattack.core.api.client.ReqResp; |  | ||||||
| import eu.mhsl.craftattack.core.util.api.WebsiteApiUtil; |  | ||||||
| import org.jetbrains.annotations.NotNull; |  | ||||||
| import org.jetbrains.annotations.Nullable; |  | ||||||
|  |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.UUID; |  | ||||||
|  |  | ||||||
| public class ReportRepository extends HttpRepository { |  | ||||||
|     public ReportRepository() { |  | ||||||
|         super(WebsiteApiUtil.getBaseUri(), WebsiteApiUtil::withAuthorizationSecret); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public record ReportCreationInfo(@NotNull UUID reporter, @Nullable UUID reported, String reason) { |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public record ReportUrl(@NotNull String url) { |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public record PlayerReports( |  | ||||||
|         List<Report> from_self, |  | ||||||
|         Object to_self |  | ||||||
|     ) { |  | ||||||
|         public record Report( |  | ||||||
|             @Nullable Reporter reported, |  | ||||||
|             @NotNull String subject, |  | ||||||
|             boolean draft, |  | ||||||
|             @NotNull String status, |  | ||||||
|             @NotNull String url |  | ||||||
|         ) { |  | ||||||
|             public record Reporter( |  | ||||||
|                 @NotNull String username, |  | ||||||
|                 @NotNull String uuid |  | ||||||
|             ) { |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public ReqResp<PlayerReports> queryReports(UUID player) { |  | ||||||
|         return this.get( |  | ||||||
|             "report", |  | ||||||
|             (parameters) -> parameters.addParameter("uuid", player.toString()), |  | ||||||
|             PlayerReports.class |  | ||||||
|         ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public ReqResp<ReportUrl> createReport(ReportCreationInfo data) { |  | ||||||
|         return this.post( |  | ||||||
|             "report", |  | ||||||
|             data, |  | ||||||
|             ReportUrl.class |  | ||||||
|         ); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,31 +0,0 @@ | |||||||
| package eu.mhsl.craftattack.core.api.client.repositories; |  | ||||||
|  |  | ||||||
| import eu.mhsl.craftattack.core.api.client.HttpRepository; |  | ||||||
| import eu.mhsl.craftattack.core.api.client.ReqResp; |  | ||||||
| import eu.mhsl.craftattack.core.util.api.WebsiteApiUtil; |  | ||||||
|  |  | ||||||
| import java.util.UUID; |  | ||||||
|  |  | ||||||
| public class WhitelistRepository extends HttpRepository { |  | ||||||
|     public WhitelistRepository() { |  | ||||||
|         super(WebsiteApiUtil.getBaseUri(), WebsiteApiUtil::withAuthorizationSecret); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public record UserData( |  | ||||||
|         UUID uuid, |  | ||||||
|         String username, |  | ||||||
|         String firstname, |  | ||||||
|         String lastname, |  | ||||||
|         Long banned_until, |  | ||||||
|         Long outlawed_until |  | ||||||
|     ) { |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public ReqResp<UserData> getUserData(UUID userId) { |  | ||||||
|         return this.get( |  | ||||||
|             "user", |  | ||||||
|             parameters -> parameters.addParameter("uuid", userId.toString()), |  | ||||||
|             UserData.class |  | ||||||
|         ); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,37 +0,0 @@ | |||||||
| package eu.mhsl.craftattack.core.util.world; |  | ||||||
|  |  | ||||||
| import net.kyori.adventure.key.Key; |  | ||||||
| import net.kyori.adventure.sound.Sound; |  | ||||||
| import org.bukkit.entity.Player; |  | ||||||
|  |  | ||||||
| public class InteractSounds { |  | ||||||
|     private final Player player; |  | ||||||
|  |  | ||||||
|     public static InteractSounds of(Player player) { |  | ||||||
|         return new InteractSounds(player); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private InteractSounds(Player player) { |  | ||||||
|         this.player = player; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void playSound(org.bukkit.Sound sound) { |  | ||||||
|         this.player.playSound(this.getSound(sound.key()), Sound.Emitter.self()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private Sound getSound(Key soundKey) { |  | ||||||
|         return Sound.sound(soundKey, Sound.Source.PLAYER, 1f, 1f); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void click() { |  | ||||||
|         this.playSound(org.bukkit.Sound.UI_BUTTON_CLICK); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void success() { |  | ||||||
|         this.playSound(org.bukkit.Sound.ENTITY_PLAYER_LEVELUP); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void delete() { |  | ||||||
|         this.playSound(org.bukkit.Sound.ENTITY_SILVERFISH_DEATH); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,9 +1,9 @@ | |||||||
| package eu.mhsl.craftattack.core; | package eu.mhsl.craftattack.spawn.core; | ||||||
| 
 | 
 | ||||||
| import eu.mhsl.craftattack.core.api.client.RepositoryLoader; | import eu.mhsl.craftattack.spawn.core.api.client.RepositoryLoader; | ||||||
| import eu.mhsl.craftattack.core.api.server.HttpServer; | import eu.mhsl.craftattack.spawn.core.api.server.HttpServer; | ||||||
| import eu.mhsl.craftattack.core.appliance.Appliance; | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
| import eu.mhsl.craftattack.core.config.Configuration; | import eu.mhsl.craftattack.spawn.core.config.Configuration; | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
| import org.bukkit.event.HandlerList; | import org.bukkit.event.HandlerList; | ||||||
| import org.bukkit.plugin.java.JavaPlugin; | import org.bukkit.plugin.java.JavaPlugin; | ||||||
| @@ -16,11 +16,13 @@ import java.util.logging.Level; | |||||||
| import java.util.logging.Logger; | import java.util.logging.Logger; | ||||||
| 
 | 
 | ||||||
| public final class Main extends JavaPlugin { | public final class Main extends JavaPlugin { | ||||||
|  |     public static final String projectPackage = "eu.mhsl.craftattack.spawn"; | ||||||
|     private static Main instance; |     private static Main instance; | ||||||
|     private static Logger logger; |     private static Logger logger; | ||||||
| 
 | 
 | ||||||
|     private List<Appliance> appliances; |     private List<Appliance> appliances; | ||||||
|     private RepositoryLoader repositoryLoader; |     private RepositoryLoader repositoryLoader; | ||||||
|  |     private Reflections reflections; | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public void onEnable() { |     public void onEnable() { | ||||||
| @@ -39,15 +41,15 @@ public final class Main extends JavaPlugin { | |||||||
|         Configuration.readConfig(); |         Configuration.readConfig(); | ||||||
|         List<String> disabledAppliances = Configuration.pluginConfig.getStringList("disabledAppliances"); |         List<String> disabledAppliances = Configuration.pluginConfig.getStringList("disabledAppliances"); | ||||||
| 
 | 
 | ||||||
|  |         Main.logger().info("Initializing reflections..."); | ||||||
|  |         this.reflections = new Reflections(projectPackage); | ||||||
|  | 
 | ||||||
|         Main.logger().info("Loading Repositories..."); |         Main.logger().info("Loading Repositories..."); | ||||||
|         this.repositoryLoader = new RepositoryLoader(); |         this.repositoryLoader = new RepositoryLoader(); | ||||||
|         Main.logger().info(String.format("Loaded %d repositories!", this.repositoryLoader.getRepositories().size())); |         Main.logger().info(String.format("Loaded %d repositories!", this.repositoryLoader.getRepositories().size())); | ||||||
| 
 | 
 | ||||||
|         Main.logger().info("Loading appliances..."); |         Main.logger().info("Loading appliances..."); | ||||||
|         Reflections reflections = new Reflections("eu.mhsl.craftattack.spawn"); |         this.appliances = this.findSubtypesOf(Appliance.class).stream() | ||||||
|         Set<Class<? extends Appliance>> applianceClasses = reflections.getSubTypesOf(Appliance.class); |  | ||||||
| 
 |  | ||||||
|         this.appliances = applianceClasses.stream() |  | ||||||
|             .filter(applianceClass -> !disabledAppliances.contains(applianceClass.getSimpleName())) |             .filter(applianceClass -> !disabledAppliances.contains(applianceClass.getSimpleName())) | ||||||
|             .map(applianceClass -> { |             .map(applianceClass -> { | ||||||
|                 try { |                 try { | ||||||
| @@ -97,6 +99,10 @@ public final class Main extends JavaPlugin { | |||||||
|             .orElseThrow(() -> new RuntimeException(String.format("Appliance %s not loaded or instantiated!", clazz))); |             .orElseThrow(() -> new RuntimeException(String.format("Appliance %s not loaded or instantiated!", clazz))); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public <T> Set<Class<? extends T>> findSubtypesOf(Class<T> type) { | ||||||
|  |         return this.reflections.getSubTypesOf(type); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @SuppressWarnings("unchecked") |     @SuppressWarnings("unchecked") | ||||||
|     public static <T> Class<T> getApplianceType(Class<?> clazz) { |     public static <T> Class<T> getApplianceType(Class<?> clazz) { | ||||||
|         return (Class<T>) ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[0]; |         return (Class<T>) ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[0]; | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| package eu.mhsl.craftattack.core.util.api; | package eu.mhsl.craftattack.spawn.core.api; | ||||||
| 
 | 
 | ||||||
| public class HttpStatus { | public class HttpStatus { | ||||||
|     public static final int OK = 200; |     public static final int OK = 200; | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.core.api.client; | package eu.mhsl.craftattack.spawn.core.api.client; | ||||||
| 
 | 
 | ||||||
| import eu.mhsl.craftattack.core.Main; | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
| import org.apache.http.client.utils.URIBuilder; | import org.apache.http.client.utils.URIBuilder; | ||||||
| import org.jetbrains.annotations.Nullable; | import org.jetbrains.annotations.Nullable; | ||||||
| 
 | 
 | ||||||
| @@ -10,23 +10,29 @@ import java.net.URISyntaxException; | |||||||
| import java.net.http.HttpClient; | import java.net.http.HttpClient; | ||||||
| import java.net.http.HttpRequest; | import java.net.http.HttpRequest; | ||||||
| import java.net.http.HttpResponse; | import java.net.http.HttpResponse; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Objects; | ||||||
| import java.util.function.Consumer; | import java.util.function.Consumer; | ||||||
| 
 | 
 | ||||||
| @RepositoryLoader.IgnoreRepository | @RepositoryLoader.Abstraction | ||||||
| public abstract class HttpRepository extends Repository { | public abstract class HttpRepository extends Repository { | ||||||
|     private final Consumer<URIBuilder> baseUriBuilder; |     public record RequestModifier( | ||||||
|  |         @Nullable Consumer<URIBuilder> uri, | ||||||
|  |         @Nullable Consumer<HttpRequest.Builder> header | ||||||
|  |     ) {} | ||||||
|  | 
 | ||||||
|  |     private final List<RequestModifier> baseRequestModifier; | ||||||
| 
 | 
 | ||||||
|     public HttpRepository(URI basePath) { |     public HttpRepository(URI basePath) { | ||||||
|         this(basePath, null); |         this(basePath, new RequestModifier(null, null)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public HttpRepository(URI basePath, @Nullable Consumer<URIBuilder> baseUriBuilder) { |     public HttpRepository(URI basePath, RequestModifier... baseRequestModifier) { | ||||||
|         super(basePath); |         super(basePath); | ||||||
| 
 | 
 | ||||||
|         this.baseUriBuilder = baseUriBuilder == null |         this.baseRequestModifier = baseRequestModifier == null | ||||||
|             ? uriBuilder -> { |             ? List.of() | ||||||
|         } |             : List.of(baseRequestModifier); | ||||||
|             : baseUriBuilder; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected <TInput, TOutput> ReqResp<TOutput> post(String command, TInput data, Class<TOutput> outputType) { |     protected <TInput, TOutput> ReqResp<TOutput> post(String command, TInput data, Class<TOutput> outputType) { | ||||||
| @@ -39,7 +45,20 @@ public abstract class HttpRepository extends Repository { | |||||||
|             .POST(HttpRequest.BodyPublishers.ofString(this.gson.toJson(data))) |             .POST(HttpRequest.BodyPublishers.ofString(this.gson.toJson(data))) | ||||||
|             .build(); |             .build(); | ||||||
| 
 | 
 | ||||||
|         return this.execute(request, outputType); |         return this.execute(request, outputType, data); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     protected <TInput, TOutput> ReqResp<TOutput> put(String command, TInput data, Class<TOutput> outputType) { | ||||||
|  |         return this.put(command, parameters -> { | ||||||
|  |         }, data, outputType); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     protected <TInput, TOutput> ReqResp<TOutput> put(String command, Consumer<URIBuilder> parameters, TInput data, Class<TOutput> outputType) { | ||||||
|  |         HttpRequest request = this.getRequestBuilder(this.getUri(command, parameters)) | ||||||
|  |             .PUT(HttpRequest.BodyPublishers.ofString(this.gson.toJson(data))) | ||||||
|  |             .build(); | ||||||
|  | 
 | ||||||
|  |         return this.execute(request, outputType, data); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected <TOutput> ReqResp<TOutput> get(String command, Class<TOutput> outputType) { |     protected <TOutput> ReqResp<TOutput> get(String command, Class<TOutput> outputType) { | ||||||
| @@ -52,13 +71,17 @@ public abstract class HttpRepository extends Repository { | |||||||
|             .GET() |             .GET() | ||||||
|             .build(); |             .build(); | ||||||
| 
 | 
 | ||||||
|         return this.execute(request, outputType); |         return this.execute(request, outputType, null); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private URI getUri(String command, Consumer<URIBuilder> parameters) { |     private URI getUri(String command, Consumer<URIBuilder> parameters) { | ||||||
|         try { |         try { | ||||||
|             URIBuilder builder = new URIBuilder(this.basePath + "/" + command); |             URIBuilder builder = new URIBuilder(this.basePath + "/" + command); | ||||||
|             this.baseUriBuilder.accept(builder); |             this.baseRequestModifier.stream() | ||||||
|  |                 .map(requestModifier -> requestModifier.uri) | ||||||
|  |                 .filter(Objects::nonNull) | ||||||
|  |                 .forEach(modifier -> modifier.accept(builder)); | ||||||
|  | 
 | ||||||
|             parameters.accept(builder); |             parameters.accept(builder); | ||||||
|             return builder.build(); |             return builder.build(); | ||||||
|         } catch(URISyntaxException e) { |         } catch(URISyntaxException e) { | ||||||
| @@ -67,14 +90,27 @@ public abstract class HttpRepository extends Repository { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private HttpRequest.Builder getRequestBuilder(URI endpoint) { |     private HttpRequest.Builder getRequestBuilder(URI endpoint) { | ||||||
|         return HttpRequest.newBuilder() |         HttpRequest.Builder builder = HttpRequest.newBuilder() | ||||||
|             .uri(endpoint) |             .uri(endpoint) | ||||||
|             .header("User-Agent", Main.instance().getServer().getBukkitVersion()) |             .header("User-Agent", Main.instance().getServer().getBukkitVersion()) | ||||||
|             .header("Content-Type", "application/json"); |             .header("Content-Type", "application/json"); | ||||||
|  | 
 | ||||||
|  |         this.baseRequestModifier.stream() | ||||||
|  |             .map(requestModifier -> requestModifier.header) | ||||||
|  |             .filter(Objects::nonNull) | ||||||
|  |             .forEach(modifier -> modifier.accept(builder)); | ||||||
|  | 
 | ||||||
|  |         return builder; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private <TResponse> ReqResp<TResponse> execute(HttpRequest request, Class<TResponse> clazz) { |     private <TResponse> ReqResp<TResponse> execute(HttpRequest request, Class<TResponse> clazz, Object original) { | ||||||
|         ReqResp<String> rawResponse = this.sendHttp(request); |         ReqResp<String> rawResponse = this.sendHttp(request); | ||||||
|  |         Main.logger().info(String.format( | ||||||
|  |             "Request: %s\nRequest-Data: %s\nResponse: %s", | ||||||
|  |             request, | ||||||
|  |             this.gson.toJson(original), | ||||||
|  |             rawResponse | ||||||
|  |         )); | ||||||
|         return new ReqResp<>(rawResponse.status(), this.gson.fromJson(rawResponse.data(), clazz)); |         return new ReqResp<>(rawResponse.status(), this.gson.fromJson(rawResponse.data(), clazz)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @@ -1,7 +1,8 @@ | |||||||
| package eu.mhsl.craftattack.core.api.client; | package eu.mhsl.craftattack.spawn.core.api.client; | ||||||
| 
 | 
 | ||||||
| import com.google.gson.Gson; | import com.google.gson.Gson; | ||||||
| import eu.mhsl.craftattack.core.Main; | import com.google.gson.GsonBuilder; | ||||||
|  | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
| 
 | 
 | ||||||
| import java.net.URI; | import java.net.URI; | ||||||
| @@ -12,7 +13,9 @@ public abstract class Repository { | |||||||
| 
 | 
 | ||||||
|     public Repository(URI basePath) { |     public Repository(URI basePath) { | ||||||
|         this.basePath = basePath; |         this.basePath = basePath; | ||||||
|         this.gson = new Gson(); |         this.gson = new GsonBuilder() | ||||||
|  |             .serializeNulls() | ||||||
|  |             .create(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected void validateThread(String commandName) { |     protected void validateThread(String commandName) { | ||||||
| @@ -1,5 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.core.api.client; | package eu.mhsl.craftattack.spawn.core.api.client; | ||||||
| 
 | 
 | ||||||
|  | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
| import org.apache.commons.lang3.NotImplementedException; | import org.apache.commons.lang3.NotImplementedException; | ||||||
| import org.reflections.Reflections; | import org.reflections.Reflections; | ||||||
| 
 | 
 | ||||||
| @@ -12,16 +13,19 @@ import java.util.Set; | |||||||
| public class RepositoryLoader { | public class RepositoryLoader { | ||||||
|     private final List<Repository> repositories; |     private final List<Repository> repositories; | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Defines a repository as an abstraction and will not be loaded by this RepositoryLoader | ||||||
|  |      */ | ||||||
|     @Retention(RetentionPolicy.RUNTIME) |     @Retention(RetentionPolicy.RUNTIME) | ||||||
|     public @interface IgnoreRepository { |     public @interface Abstraction { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public RepositoryLoader() { |     public RepositoryLoader() { | ||||||
|         Reflections reflections = new Reflections(this.getClass().getPackageName()); |         Reflections reflections = new Reflections(Main.projectPackage); | ||||||
|         Set<Class<? extends Repository>> repositories = reflections.getSubTypesOf(Repository.class); |         Set<Class<? extends Repository>> repositories = reflections.getSubTypesOf(Repository.class); | ||||||
| 
 | 
 | ||||||
|         this.repositories = repositories.stream() |         this.repositories = repositories.stream() | ||||||
|             .filter(repository -> !repository.isAnnotationPresent(IgnoreRepository.class)) |             .filter(repository -> !repository.isAnnotationPresent(Abstraction.class)) | ||||||
|             .map(repository -> { |             .map(repository -> { | ||||||
|                 try { |                 try { | ||||||
|                     return (Repository) repository.getDeclaredConstructor().newInstance(); |                     return (Repository) repository.getDeclaredConstructor().newInstance(); | ||||||
| @@ -0,0 +1,16 @@ | |||||||
|  | package eu.mhsl.craftattack.spawn.core.api.client; | ||||||
|  |  | ||||||
|  | import com.google.gson.Gson; | ||||||
|  | import java.lang.reflect.Type; | ||||||
|  |  | ||||||
|  | public record ReqResp<TData>(int status, TData data) { | ||||||
|  |     public ReqResp<?> convertToTypeToken(Type type) { | ||||||
|  |         var gson = new Gson(); | ||||||
|  |         return new ReqResp<>(this.status, gson.fromJson(gson.toJson(this.data), type)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @SuppressWarnings("unchecked") | ||||||
|  |     public <T> T cast() { | ||||||
|  |         return (T) this; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,8 +1,8 @@ | |||||||
| package eu.mhsl.craftattack.core.api.server; | package eu.mhsl.craftattack.spawn.core.api.server; | ||||||
| 
 | 
 | ||||||
| import com.google.gson.Gson; | import com.google.gson.Gson; | ||||||
| import eu.mhsl.craftattack.core.Main; | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
| import eu.mhsl.craftattack.core.appliance.Appliance; | import eu.mhsl.craftattack.spawn.core.appliance.Appliance; | ||||||
| import org.bukkit.configuration.ConfigurationSection; | import org.bukkit.configuration.ConfigurationSection; | ||||||
| import spark.Request; | import spark.Request; | ||||||
| import spark.Spark; | import spark.Spark; | ||||||
| @@ -1,9 +1,9 @@ | |||||||
| package eu.mhsl.craftattack.core.appliance; | package eu.mhsl.craftattack.spawn.core.appliance; | ||||||
| 
 | 
 | ||||||
| import eu.mhsl.craftattack.core.Main; | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
| import eu.mhsl.craftattack.core.api.client.Repository; | import eu.mhsl.craftattack.spawn.core.api.client.Repository; | ||||||
| import eu.mhsl.craftattack.core.api.server.HttpServer; | import eu.mhsl.craftattack.spawn.core.api.server.HttpServer; | ||||||
| import eu.mhsl.craftattack.core.config.Configuration; | import eu.mhsl.craftattack.spawn.core.config.Configuration; | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
| import org.bukkit.command.PluginCommand; | import org.bukkit.command.PluginCommand; | ||||||
| import org.bukkit.configuration.ConfigurationSection; | import org.bukkit.configuration.ConfigurationSection; | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.core.appliance; | package eu.mhsl.craftattack.spawn.core.appliance; | ||||||
| 
 | 
 | ||||||
| import eu.mhsl.craftattack.core.Main; | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.format.NamedTextColor; | import net.kyori.adventure.text.format.NamedTextColor; | ||||||
| import org.bukkit.command.Command; | import org.bukkit.command.Command; | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| package eu.mhsl.craftattack.core.appliance; | package eu.mhsl.craftattack.spawn.core.appliance; | ||||||
| 
 | 
 | ||||||
| import org.bukkit.event.Listener; | import org.bukkit.event.Listener; | ||||||
| 
 | 
 | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.core.appliance; | package eu.mhsl.craftattack.spawn.core.appliance; | ||||||
| 
 | 
 | ||||||
| import eu.mhsl.craftattack.core.Main; | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
| 
 | 
 | ||||||
| public class CachedApplianceSupplier<T extends Appliance> implements IApplianceSupplier<T> { | public class CachedApplianceSupplier<T extends Appliance> implements IApplianceSupplier<T> { | ||||||
|     private final T appliance; |     private final T appliance; | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| package eu.mhsl.craftattack.core.appliance; | package eu.mhsl.craftattack.spawn.core.appliance; | ||||||
| 
 | 
 | ||||||
| public interface IApplianceSupplier<T extends Appliance> { | public interface IApplianceSupplier<T extends Appliance> { | ||||||
|     T getAppliance(); |     T getAppliance(); | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| package eu.mhsl.craftattack.core.config; | package eu.mhsl.craftattack.spawn.core.config; | ||||||
| 
 | 
 | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
| import org.bukkit.Location; | import org.bukkit.Location; | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| package eu.mhsl.craftattack.core.config; | package eu.mhsl.craftattack.spawn.core.config; | ||||||
| 
 | 
 | ||||||
| import eu.mhsl.craftattack.core.Main; | import eu.mhsl.craftattack.spawn.core.Main; | ||||||
| import org.bukkit.configuration.ConfigurationSection; | import org.bukkit.configuration.ConfigurationSection; | ||||||
| import org.bukkit.configuration.file.FileConfiguration; | import org.bukkit.configuration.file.FileConfiguration; | ||||||
| import org.bukkit.configuration.file.YamlConfiguration; | import org.bukkit.configuration.file.YamlConfiguration; | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user