Merge remote-tracking branch 'origin/develop-chatReply' into develop-chatReply
This commit is contained in:
commit
d8259b79ae
@ -26,6 +26,7 @@ dependencies {
|
||||
compileOnly 'org.geysermc.floodgate:api:2.2.2-SNAPSHOT'
|
||||
implementation 'org.apache.httpcomponents:httpclient:4.5.14'
|
||||
implementation 'com.sparkjava:spark-core:2.9.4'
|
||||
implementation 'org.reflections:reflections:0.10.2'
|
||||
}
|
||||
|
||||
def targetJavaVersion = 21
|
||||
|
@ -2,39 +2,16 @@ package eu.mhsl.craftattack.spawn;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.api.HttpServer;
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.appliances.antiSignEdit.AntiSignEdit;
|
||||
import eu.mhsl.craftattack.spawn.appliances.adminMarker.AdminMarker;
|
||||
import eu.mhsl.craftattack.spawn.appliances.autoShulker.AutoShulker;
|
||||
import eu.mhsl.craftattack.spawn.appliances.chatMention.ChatMention;
|
||||
import eu.mhsl.craftattack.spawn.appliances.chatMessages.ChatMessages;
|
||||
import eu.mhsl.craftattack.spawn.appliances.customAdvancements.CustomAdvancements;
|
||||
import eu.mhsl.craftattack.spawn.appliances.debug.Debug;
|
||||
import eu.mhsl.craftattack.spawn.appliances.displayName.DisplayName;
|
||||
import eu.mhsl.craftattack.spawn.appliances.event.Event;
|
||||
import eu.mhsl.craftattack.spawn.appliances.fleischerchest.Fleischerchest;
|
||||
import eu.mhsl.craftattack.spawn.appliances.help.Help;
|
||||
import eu.mhsl.craftattack.spawn.appliances.hotbarRefill.HotbarRefill;
|
||||
import eu.mhsl.craftattack.spawn.appliances.kick.Kick;
|
||||
import eu.mhsl.craftattack.spawn.appliances.outlawed.Outlawed;
|
||||
import eu.mhsl.craftattack.spawn.appliances.panicBan.PanicBan;
|
||||
import eu.mhsl.craftattack.spawn.appliances.playerlimit.PlayerLimit;
|
||||
import eu.mhsl.craftattack.spawn.appliances.portableCrafting.PortableCrafting;
|
||||
import eu.mhsl.craftattack.spawn.appliances.privateMessage.PrivateMessage;
|
||||
import eu.mhsl.craftattack.spawn.appliances.projectStart.ProjectStart;
|
||||
import eu.mhsl.craftattack.spawn.appliances.report.Report;
|
||||
import eu.mhsl.craftattack.spawn.appliances.restart.Restart;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.Settings;
|
||||
import eu.mhsl.craftattack.spawn.appliances.tablist.Tablist;
|
||||
import eu.mhsl.craftattack.spawn.appliances.titleClear.TitleClear;
|
||||
import eu.mhsl.craftattack.spawn.appliances.whitelist.Whitelist;
|
||||
import eu.mhsl.craftattack.spawn.appliances.worldmuseum.WorldMuseum;
|
||||
import eu.mhsl.craftattack.spawn.config.Configuration;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public final class Main extends JavaPlugin {
|
||||
@ -49,49 +26,46 @@ public final class Main extends JavaPlugin {
|
||||
instance = this;
|
||||
logger = instance().getLogger();
|
||||
saveDefaultConfig();
|
||||
Configuration.readConfig();
|
||||
try {
|
||||
this.wrappedEnable();
|
||||
} catch (Exception e) {
|
||||
Main.logger().log(Level.SEVERE, "Error while initializing Spawn plugin, shutting down!", e);
|
||||
Bukkit.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
appliances = List.of(
|
||||
new AdminMarker(),
|
||||
new WorldMuseum(),
|
||||
new TitleClear(),
|
||||
new ProjectStart(),
|
||||
new Tablist(),
|
||||
new ChatMessages(),
|
||||
new Report(),
|
||||
new Event(),
|
||||
new Help(),
|
||||
new PlayerLimit(),
|
||||
new Whitelist(),
|
||||
new Restart(),
|
||||
new Kick(),
|
||||
new PanicBan(),
|
||||
new Outlawed(),
|
||||
new DisplayName(),
|
||||
new Debug(),
|
||||
new Fleischerchest(),
|
||||
new CustomAdvancements(),
|
||||
new Settings(),
|
||||
new PortableCrafting(),
|
||||
new AutoShulker(),
|
||||
new AntiSignEdit(),
|
||||
new HotbarRefill(),
|
||||
new ChatMention(),
|
||||
new PrivateMessage()
|
||||
);
|
||||
private void wrappedEnable() {
|
||||
Configuration.readConfig();
|
||||
List<String> disabledAppliances = Configuration.pluginConfig.getStringList("disabledAppliances");
|
||||
|
||||
Main.logger.info("Loading appliances...");
|
||||
appliances.forEach(appliance -> {
|
||||
Main.logger().info("Enabling " + appliance.getClass().getSimpleName());
|
||||
Reflections reflections = new Reflections(this.getClass().getPackageName());
|
||||
Set<Class<? extends Appliance>> applianceClasses = reflections.getSubTypesOf(Appliance.class);
|
||||
|
||||
this.appliances = applianceClasses.stream()
|
||||
.filter(applianceClass -> !disabledAppliances.contains(applianceClass.getSimpleName()))
|
||||
.map(applianceClass -> {
|
||||
try {
|
||||
return (Appliance) applianceClass.getDeclaredConstructor().newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(String.format("Failed to create instance of '%s'", applianceClass.getName()), e);
|
||||
}
|
||||
})
|
||||
.toList();
|
||||
Main.logger().info(String.format("Loaded %d appliances!", appliances.size()));
|
||||
|
||||
Main.logger().info("Initializing appliances...");
|
||||
this.appliances.forEach(appliance -> {
|
||||
appliance.onEnable();
|
||||
appliance.initialize(this);
|
||||
});
|
||||
Main.logger().info("Loaded " + appliances.size() + " appliances!");
|
||||
Main.logger().info(String.format("Initialized %d appliances!", appliances.size()));
|
||||
|
||||
Main.logger().info("Starting HTTP API");
|
||||
Main.logger().info("Starting HTTP API...");
|
||||
this.httpApi = new HttpServer();
|
||||
|
||||
getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord");
|
||||
Main.logger().info("Startup complete!");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -42,7 +42,7 @@ public abstract class Appliance {
|
||||
* @return List of listeners
|
||||
*/
|
||||
@NotNull
|
||||
protected List<Listener> eventHandlers() {
|
||||
protected List<Listener> listeners() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@ -72,7 +72,8 @@ public abstract class Appliance {
|
||||
*/
|
||||
@NotNull
|
||||
public ConfigurationSection localConfig() {
|
||||
return Optional.ofNullable(Configuration.cfg.getConfigurationSection(localConfigPath)).orElse(Configuration.cfg);
|
||||
return Optional.ofNullable(Configuration.cfg.getConfigurationSection(localConfigPath))
|
||||
.orElseGet(() -> Configuration.cfg.createSection(localConfigPath));
|
||||
}
|
||||
|
||||
public void onEnable() {
|
||||
@ -82,7 +83,7 @@ public abstract class Appliance {
|
||||
}
|
||||
|
||||
public void initialize(@NotNull JavaPlugin plugin) {
|
||||
this.listeners = eventHandlers();
|
||||
this.listeners = listeners();
|
||||
this.commands = commands();
|
||||
|
||||
listeners.forEach(listener -> Bukkit.getPluginManager().registerEvents(listener, plugin));
|
||||
@ -93,7 +94,7 @@ public abstract class Appliance {
|
||||
listeners.forEach(HandlerList::unregisterAll);
|
||||
}
|
||||
|
||||
public <T extends Appliance> T queryAppliance(Class<T> clazz) {
|
||||
protected static <T extends Appliance> T queryAppliance(Class<T> clazz) {
|
||||
return Main.instance().getAppliance(clazz);
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ import java.util.Optional;
|
||||
/**
|
||||
* Utility class which enables command name definition over a constructor.
|
||||
*/
|
||||
public abstract class ApplianceCommand<T extends Appliance> extends ApplianceSupplier<T> implements TabCompleter, CommandExecutor {
|
||||
public abstract class ApplianceCommand<T extends Appliance> extends CachedApplianceSupplier<T> implements TabCompleter, CommandExecutor {
|
||||
public String commandName;
|
||||
protected Component errorMessage = Component.text("Fehler: ").color(NamedTextColor.RED);
|
||||
|
||||
|
@ -8,6 +8,6 @@ import org.bukkit.event.Listener;
|
||||
*
|
||||
* @param <T> the type of your appliance
|
||||
*/
|
||||
public abstract class ApplianceListener<T extends Appliance> extends ApplianceSupplier<T> implements Listener {
|
||||
public abstract class ApplianceListener<T extends Appliance> extends CachedApplianceSupplier<T> implements Listener {
|
||||
|
||||
}
|
@ -2,10 +2,10 @@ package eu.mhsl.craftattack.spawn.appliance;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.Main;
|
||||
|
||||
public class ApplianceSupplier<T extends Appliance> implements IApplianceSupplier<T> {
|
||||
public class CachedApplianceSupplier<T extends Appliance> implements IApplianceSupplier<T> {
|
||||
private final T appliance;
|
||||
|
||||
public ApplianceSupplier() {
|
||||
public CachedApplianceSupplier() {
|
||||
this.appliance = Main.instance().getAppliance(Main.getApplianceType(getClass()));
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ public class AdminMarker extends Appliance {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected List<Listener> eventHandlers() {
|
||||
protected List<Listener> listeners() {
|
||||
return List.of(new AdminMarkerListener());
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package eu.mhsl.craftattack.spawn.appliances.antiSignEdit;
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.Settings;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.datatypes.SelectSetting;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.settings.SignEditSetting;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
@ -15,6 +14,11 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
public class AntiSignEdit extends Appliance {
|
||||
@Override
|
||||
public void onEnable() {
|
||||
Settings.instance().declareSetting(SignEditSetting.class);
|
||||
}
|
||||
|
||||
public boolean preventSignEdit(Player p, SignSide sign) {
|
||||
SelectSetting.Options.Option setting = Settings.instance().getSetting(p, Settings.Key.SignEdit, SelectSetting.Options.Option.class);
|
||||
if(setting.is(SignEditSetting.editable)) return false;
|
||||
@ -37,7 +41,7 @@ public class AntiSignEdit extends Appliance {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<Listener> eventHandlers() {
|
||||
protected @NotNull List<Listener> listeners() {
|
||||
return List.of(new OnSignEditListener());
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.settings.settings;
|
||||
package eu.mhsl.craftattack.spawn.appliances.antiSignEdit;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.CategorizedSetting;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.SettingCategory;
|
@ -1,6 +1,7 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.autoShulker;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.Settings;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.Material;
|
||||
@ -16,6 +17,11 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class AutoShulker extends Appliance {
|
||||
@Override
|
||||
public void onEnable() {
|
||||
Settings.instance().declareSetting(AutoShulkerSetting.class);
|
||||
}
|
||||
|
||||
public boolean tryAutoShulker(Player p, Item item) {
|
||||
ItemStack itemStack = item.getItemStack();
|
||||
ItemStack offhandStack = p.getInventory().getItemInOffHand();
|
||||
@ -40,7 +46,7 @@ public class AutoShulker extends Appliance {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<Listener> eventHandlers() {
|
||||
protected @NotNull List<Listener> listeners() {
|
||||
return List.of(new ItemPickupListener());
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.settings.settings;
|
||||
package eu.mhsl.craftattack.spawn.appliances.autoShulker;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.CategorizedSetting;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.SettingCategory;
|
@ -3,7 +3,6 @@ package eu.mhsl.craftattack.spawn.appliances.autoShulker;
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.Settings;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.datatypes.SelectSetting;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.settings.AutoShulkerSetting;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.entity.EntityPickupItemEvent;
|
||||
|
@ -3,7 +3,6 @@ package eu.mhsl.craftattack.spawn.appliances.chatMention;
|
||||
import eu.mhsl.craftattack.spawn.Main;
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.Settings;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.settings.ChatMentionSetting;
|
||||
import net.kyori.adventure.sound.Sound;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
@ -56,11 +55,12 @@ public class ChatMention extends Appliance {
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
Settings.instance().declareSetting(ChatMentionSetting.class);
|
||||
refreshPlayers();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<Listener> eventHandlers() {
|
||||
protected @NotNull List<Listener> listeners() {
|
||||
return List.of(new ChatMentionListener());
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import eu.mhsl.craftattack.spawn.Main;
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||
import eu.mhsl.craftattack.spawn.appliances.chatMessages.ChatMessages;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.Settings;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.settings.ChatMentionSetting;
|
||||
import eu.mhsl.craftattack.spawn.util.text.ComponentUtil;
|
||||
import io.papermc.paper.event.player.AsyncChatDecorateEvent;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
@ -42,7 +42,7 @@ public class ChatMentionListener extends ApplianceListener<ChatMention> {
|
||||
return Component.text(word);
|
||||
}
|
||||
})
|
||||
.reduce((a, b) -> a.append(Component.text(" ")).append(b))
|
||||
.reduce(ComponentUtil::appendWithSpace)
|
||||
.orElseThrow();
|
||||
|
||||
getAppliance().notifyPlayers(mentioned);
|
||||
|
@ -1,4 +1,4 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.settings.settings;
|
||||
package eu.mhsl.craftattack.spawn.appliances.chatMention;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.CategorizedSetting;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.SettingCategory;
|
||||
@ -9,7 +9,7 @@ import org.bukkit.Material;
|
||||
public class ChatMentionSetting extends MultiBoolSetting<ChatMentionSetting.ChatMentionConfig> implements CategorizedSetting {
|
||||
@Override
|
||||
public SettingCategory category() {
|
||||
return SettingCategory.Chat;
|
||||
return SettingCategory.Visuals;
|
||||
}
|
||||
|
||||
public record ChatMentionConfig(
|
@ -1,6 +1,7 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.chatMessages;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.Settings;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
@ -12,6 +13,11 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
public class ChatMessages extends Appliance {
|
||||
@Override
|
||||
public void onEnable() {
|
||||
Settings.instance().declareSetting(ShowJoinAndLeaveMessagesSetting.class);
|
||||
}
|
||||
|
||||
public Component getReportablePlayerName(Player player) {
|
||||
return addReportActions(player.displayName(), player.getName());
|
||||
}
|
||||
@ -24,7 +30,7 @@ public class ChatMessages extends Appliance {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected List<Listener> eventHandlers() {
|
||||
protected List<Listener> listeners() {
|
||||
return List.of(new ChatMessagesListener());
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.settings.settings;
|
||||
package eu.mhsl.craftattack.spawn.appliances.chatMessages;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.CategorizedSetting;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.SettingCategory;
|
||||
@ -33,6 +33,6 @@ public class ShowJoinAndLeaveMessagesSetting extends BoolSetting implements Cate
|
||||
|
||||
@Override
|
||||
public SettingCategory category() {
|
||||
return SettingCategory.Chat;
|
||||
return SettingCategory.Visuals;
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@ public class CustomAdvancements extends Appliance {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected List<Listener> eventHandlers() {
|
||||
protected List<Listener> listeners() {
|
||||
return List.of(new CustomAdvancementsDamageEntityListener());
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.customAdvancements;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
@ -9,12 +9,11 @@ import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
public class CustomAdvancementsDamageEntityListener extends ApplianceListener<CustomAdvancements> {
|
||||
@EventHandler
|
||||
public void onEntityDamageEntity(EntityDamageByEntityEvent event) {
|
||||
Entity damaged = event.getEntity();
|
||||
if(!(damaged instanceof Player)) return;
|
||||
Entity damager = event.getDamager();
|
||||
if(!(damager instanceof Player)) return;
|
||||
if(damaged.hasPermission("admin")) {
|
||||
getAppliance().grantAdvancement("search_trouble", (Player) damager);
|
||||
}
|
||||
if(!(event.getEntity() instanceof Player damaged)) return;
|
||||
if(!(event.getDamager() instanceof Player damager)) return;
|
||||
if(!damager.getInventory().getItemInMainHand().getType().equals(Material.AIR)) return;
|
||||
if(!damaged.hasPermission("admin")) return;
|
||||
|
||||
getAppliance().grantAdvancement("search_trouble", damager);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.displayName;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.Main;
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.appliances.adminMarker.AdminMarker;
|
||||
import eu.mhsl.craftattack.spawn.appliances.adminMarker.AdminMarkerListener;
|
||||
import eu.mhsl.craftattack.spawn.appliances.outlawed.Outlawed;
|
||||
import eu.mhsl.craftattack.spawn.appliances.yearRank.YearRank;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.ComponentBuilder;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
@ -14,19 +16,22 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class DisplayName extends Appliance {
|
||||
public void update(Player player) {
|
||||
TextColor playerColor = queryAppliance(AdminMarker.class).getPlayerColor(player);
|
||||
List<Supplier<Component>> prefixes = List.of(
|
||||
() -> queryAppliance(Outlawed.class).getNamePrefix(player)
|
||||
() -> queryAppliance(Outlawed.class).getNamePrefix(player),
|
||||
() -> queryAppliance(YearRank.class).getNamePrefix(player)
|
||||
);
|
||||
|
||||
ComponentBuilder<TextComponent, TextComponent.Builder> playerName = Component.text();
|
||||
prefixes.forEach(supplier -> {
|
||||
Component prefix = supplier.get();
|
||||
if(prefix == null) return;
|
||||
playerName.append(prefix).append(Component.text(" "));
|
||||
playerName.append(prefix).append(
|
||||
Component.text(" ").hoverEvent(Component.empty().asHoverEvent()));
|
||||
});
|
||||
|
||||
playerName.append(Component.text(player.getName(), playerColor));
|
||||
@ -41,14 +46,14 @@ public class DisplayName extends Appliance {
|
||||
player.playerListName(component);
|
||||
} catch(Exception e) {
|
||||
//TODO this throws often exceptions, but still works, don't know why
|
||||
//Main.instance().getLogger().log(Level.SEVERE, e, e::getMessage);
|
||||
Main.instance().getLogger().log(Level.SEVERE, e, e::getMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected List<Listener> eventHandlers() {
|
||||
protected List<Listener> listeners() {
|
||||
return List.of(new AdminMarkerListener());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,50 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.doubeDoor;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.Settings;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.type.Door;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class DoubleDoor extends Appliance {
|
||||
@Override
|
||||
public void onEnable() {
|
||||
Settings.instance().declareSetting(DoubleDoorSetting.class);
|
||||
}
|
||||
|
||||
public void openNextDoor(Block block) {
|
||||
BlockData clickedData = block.getBlockData();
|
||||
if (!(clickedData instanceof Door clickedDoor)) return;
|
||||
|
||||
BlockFace neighborFace = getNeighborFace(clickedDoor.getFacing(), clickedDoor.getHinge());
|
||||
Block neighbourBlock = block.getRelative(neighborFace);
|
||||
BlockData neighbourData = neighbourBlock.getBlockData();
|
||||
|
||||
if(!(neighbourData instanceof Door neighbourDoor)) return;
|
||||
if(!(neighbourDoor.getFacing() == clickedDoor.getFacing())) return;
|
||||
if(neighbourDoor.getHinge() == clickedDoor.getHinge()) return;
|
||||
|
||||
neighbourDoor.setOpen(!clickedDoor.isOpen());
|
||||
neighbourBlock.setBlockData(neighbourDoor);
|
||||
}
|
||||
|
||||
private @NotNull BlockFace getNeighborFace(BlockFace face, Door.Hinge hinge) {
|
||||
return switch(face) {
|
||||
case EAST -> (hinge == Door.Hinge.RIGHT) ? BlockFace.NORTH : BlockFace.SOUTH;
|
||||
case WEST -> (hinge == Door.Hinge.RIGHT) ? BlockFace.SOUTH : BlockFace.NORTH;
|
||||
case SOUTH -> (hinge == Door.Hinge.RIGHT) ? BlockFace.EAST : BlockFace.WEST;
|
||||
case NORTH -> (hinge == Door.Hinge.RIGHT) ? BlockFace.WEST : BlockFace.EAST;
|
||||
default -> throw new IllegalStateException(String.format("BlockFace '%s' of clicked door is not valid!", face));
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<Listener> listeners() {
|
||||
return List.of(new OnDoorInteractListener());
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.doubeDoor;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.CategorizedSetting;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.SettingCategory;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.Settings;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.datatypes.BoolSetting;
|
||||
import org.bukkit.Material;
|
||||
|
||||
public class DoubleDoorSetting extends BoolSetting implements CategorizedSetting {
|
||||
public DoubleDoorSetting() {
|
||||
super(Settings.Key.DoubleDoors);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String title() {
|
||||
return "Automatische Doppeltüren";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String description() {
|
||||
return "Öffnet und schließt die zweite Hälfte einer Doppeltür automatisch";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Material icon() {
|
||||
return Material.OAK_DOOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean defaultValue() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SettingCategory category() {
|
||||
return SettingCategory.Gameplay;
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.doubeDoor;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.Settings;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class OnDoorInteractListener extends ApplianceListener<DoubleDoor> {
|
||||
@EventHandler
|
||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||
if(!event.hasBlock()) return;
|
||||
if(!Objects.equals(event.getHand(), EquipmentSlot.HAND)) return;
|
||||
if(!event.getAction().equals(Action.RIGHT_CLICK_BLOCK)) return;
|
||||
if(event.getPlayer().isSneaking()) return;
|
||||
Block clickedBlock = event.getClickedBlock();
|
||||
if(clickedBlock == null) return;
|
||||
if(clickedBlock.getType().equals(Material.IRON_DOOR)) return;
|
||||
if(!Settings.instance().getSetting(event.getPlayer(), Settings.Key.DoubleDoors, Boolean.class)) return;
|
||||
getAppliance().openNextDoor(clickedBlock);
|
||||
}
|
||||
}
|
@ -201,17 +201,15 @@ public class Event extends Appliance {
|
||||
public void advertise() {
|
||||
advertiseCountdown.cancelIfRunning();
|
||||
this.advertiseStatus = AdvertisementStatus.ADVERTISED;
|
||||
IteratorUtil.onlinePlayers(player -> {
|
||||
player.sendMessage(
|
||||
Component.text()
|
||||
.append(Component.text("-".repeat(10), NamedTextColor.GRAY)).appendNewline()
|
||||
.append(Component.text("Ein Event wurde gestartet!", NamedTextColor.GOLD)).appendNewline()
|
||||
.append(Component.text("Nutze "))
|
||||
.append(Component.text("/event", NamedTextColor.AQUA))
|
||||
.append(Component.text(", um dem Event beizutreten!")).appendNewline()
|
||||
.append(Component.text("-".repeat(10), NamedTextColor.GRAY)).appendNewline()
|
||||
);
|
||||
});
|
||||
IteratorUtil.onlinePlayers(player -> player.sendMessage(
|
||||
Component.text()
|
||||
.append(Component.text("-".repeat(10), NamedTextColor.GRAY)).appendNewline()
|
||||
.append(Component.text("Ein Event wurde gestartet!", NamedTextColor.GOLD)).appendNewline()
|
||||
.append(Component.text("Nutze "))
|
||||
.append(Component.text("/event", NamedTextColor.AQUA))
|
||||
.append(Component.text(", um dem Event beizutreten!")).appendNewline()
|
||||
.append(Component.text("-".repeat(10), NamedTextColor.GRAY)).appendNewline()
|
||||
));
|
||||
advertiseCountdown.start();
|
||||
}
|
||||
|
||||
@ -237,7 +235,7 @@ public class Event extends Appliance {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected List<Listener> eventHandlers() {
|
||||
protected List<Listener> listeners() {
|
||||
return List.of(
|
||||
new ApplyPendingRewardsListener(),
|
||||
new PlayerInteractAtEntityEventListener(this.villager.getUniqueId(), playerInteractAtEntityEvent -> joinEvent(playerInteractAtEntityEvent.getPlayer())),
|
||||
|
@ -19,7 +19,7 @@ public class Fleischerchest extends Appliance {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected List<Listener> eventHandlers() {
|
||||
protected List<Listener> listeners() {
|
||||
return List.of(new FleischerchestCraftItemListener());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.glowingBerries;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import net.kyori.adventure.sound.Sound;
|
||||
import net.kyori.adventure.util.Ticks;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class GlowingBerries extends Appliance {
|
||||
private static final PotionEffect glowEffect = new PotionEffect(
|
||||
PotionEffectType.GLOWING,
|
||||
Ticks.TICKS_PER_SECOND * 15,
|
||||
1,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
public void letPlayerGlow(Player player) {
|
||||
player.addPotionEffect(glowEffect);
|
||||
Sound sound = Sound.sound(org.bukkit.Sound.BLOCK_AMETHYST_BLOCK_CHIME.key(), Sound.Source.PLAYER, 1f, 1f);
|
||||
player.stopSound(sound);
|
||||
player.playSound(sound, Sound.Emitter.self());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<Listener> listeners() {
|
||||
return List.of(new OnBerryEaten());
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.glowingBerries;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.player.PlayerItemConsumeEvent;
|
||||
|
||||
public class OnBerryEaten extends ApplianceListener<GlowingBerries> {
|
||||
@EventHandler
|
||||
public void onEat(PlayerItemConsumeEvent event) {
|
||||
if(event.getItem().getType().equals(Material.GLOW_BERRIES)) getAppliance().letPlayerGlow(event.getPlayer());
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package eu.mhsl.craftattack.spawn.appliances.hotbarRefill;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.Main;
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.Settings;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.Bukkit;
|
||||
@ -16,6 +17,11 @@ import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public class HotbarRefill extends Appliance {
|
||||
@Override
|
||||
public void onEnable() {
|
||||
Settings.instance().declareSetting(HotbarRefillSetting.class);
|
||||
}
|
||||
|
||||
public void handleHotbarChange(Player player, ItemStack item) {
|
||||
if(player.getGameMode().equals(GameMode.CREATIVE)) return;
|
||||
if(item.getAmount() != 1) return;
|
||||
@ -46,7 +52,7 @@ public class HotbarRefill extends Appliance {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<Listener> eventHandlers() {
|
||||
return List.of(new ItemRefillListener());
|
||||
protected @NotNull List<Listener> listeners() {
|
||||
return List.of(new HotbarRefillListener());
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package eu.mhsl.craftattack.spawn.appliances.hotbarRefill;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.Settings;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.settings.HotbarReplaceSetting;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
@ -10,12 +9,12 @@ import org.bukkit.event.player.PlayerItemBreakEvent;
|
||||
import org.bukkit.event.player.PlayerItemConsumeEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class ItemRefillListener extends ApplianceListener<HotbarRefill> {
|
||||
private HotbarReplaceSetting.HotbarReplaceConfig getPlayerSetting(Player player) {
|
||||
public class HotbarRefillListener extends ApplianceListener<HotbarRefill> {
|
||||
private HotbarRefillSetting.HotbarReplaceConfig getPlayerSetting(Player player) {
|
||||
return Settings.instance().getSetting(
|
||||
player,
|
||||
Settings.Key.HotbarReplacer,
|
||||
HotbarReplaceSetting.HotbarReplaceConfig.class
|
||||
HotbarRefillSetting.HotbarReplaceConfig.class
|
||||
);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.settings.settings;
|
||||
package eu.mhsl.craftattack.spawn.appliances.hotbarRefill;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.CategorizedSetting;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.SettingCategory;
|
||||
@ -6,7 +6,7 @@ import eu.mhsl.craftattack.spawn.appliances.settings.Settings;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.datatypes.MultiBoolSetting;
|
||||
import org.bukkit.Material;
|
||||
|
||||
public class HotbarReplaceSetting extends MultiBoolSetting<HotbarReplaceSetting.HotbarReplaceConfig> implements CategorizedSetting {
|
||||
public class HotbarRefillSetting extends MultiBoolSetting<HotbarRefillSetting.HotbarReplaceConfig> implements CategorizedSetting {
|
||||
@Override
|
||||
public SettingCategory category() {
|
||||
return SettingCategory.Gameplay;
|
||||
@ -18,7 +18,7 @@ public class HotbarReplaceSetting extends MultiBoolSetting<HotbarReplaceSetting.
|
||||
@DisplayName("Essen") boolean onConsumable
|
||||
) {}
|
||||
|
||||
public HotbarReplaceSetting() {
|
||||
public HotbarRefillSetting() {
|
||||
super(Settings.Key.HotbarReplacer);
|
||||
}
|
||||
|
@ -0,0 +1,65 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.knockDoor;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.Main;
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.Settings;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.datatypes.SelectSetting;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class KnockDoor extends Appliance {
|
||||
@Override
|
||||
public void onEnable() {
|
||||
Settings.instance().declareSetting(KnockDoorSetting.class);
|
||||
}
|
||||
|
||||
public void knockAtDoor(Player knockingPlayer, Block knockedBlock) {
|
||||
SelectSetting.Options.Option setting = Settings.instance().getSetting(knockingPlayer, Settings.Key.KnockDoors, SelectSetting.Options.Option.class);
|
||||
if(setting.is(KnockDoorSetting.disabled)) return;
|
||||
|
||||
if(setting.is(KnockDoorSetting.knockSingleTime)) {
|
||||
playSound(knockedBlock);
|
||||
}
|
||||
|
||||
if(setting.is(KnockDoorSetting.knockThreeTimes)) {
|
||||
String metadataKey = new NamespacedKey(Main.instance(), KnockDoor.class.getName()).getNamespace();
|
||||
if(knockingPlayer.hasMetadata(metadataKey)) return;
|
||||
knockingPlayer.setMetadata(metadataKey, new FixedMetadataValue(Main.instance(), 0));
|
||||
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int timesKnocked = knockingPlayer.getMetadata(metadataKey).getFirst().asInt();
|
||||
if(timesKnocked >= 3) {
|
||||
knockingPlayer.removeMetadata(metadataKey, Main.instance());
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
playSound(knockedBlock);
|
||||
knockingPlayer.setMetadata(metadataKey, new FixedMetadataValue(Main.instance(), timesKnocked + 1));
|
||||
}
|
||||
}.runTaskTimer(Main.instance(), 0, 8);
|
||||
}
|
||||
}
|
||||
|
||||
private void playSound(Block knockedBlock) {
|
||||
Location knockLocation = knockedBlock.getLocation();
|
||||
Sound sound = knockedBlock.getType() == Material.IRON_DOOR
|
||||
? Sound.ENTITY_ZOMBIE_ATTACK_IRON_DOOR
|
||||
: Sound.ITEM_SHIELD_BLOCK;
|
||||
|
||||
knockLocation.getWorld().playSound(knockLocation, sound, SoundCategory.PLAYERS, 1f, 1f);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<Listener> listeners() {
|
||||
return List.of(new KnockDoorListener());
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.knockDoor;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.type.Door;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.block.BlockDamageAbortEvent;
|
||||
|
||||
public class KnockDoorListener extends ApplianceListener<KnockDoor> {
|
||||
@EventHandler
|
||||
public void onKnock(BlockDamageAbortEvent event) {
|
||||
if(event.getPlayer().getGameMode() != GameMode.SURVIVAL) return;
|
||||
Block block = event.getBlock();
|
||||
if(!(block.getBlockData() instanceof Door)) return;
|
||||
getAppliance().knockAtDoor(event.getPlayer(), block);
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.knockDoor;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.CategorizedSetting;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.SettingCategory;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.Settings;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.datatypes.SelectSetting;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class KnockDoorSetting extends SelectSetting implements CategorizedSetting {
|
||||
private static final String namespace = KnockDoorSetting.class.getSimpleName().toLowerCase(Locale.ROOT);
|
||||
public static Options.Option disabled = new Options.Option("Deaktiviert", new NamespacedKey(namespace, "disabled"));
|
||||
public static Options.Option knockSingleTime = new Options.Option("Einmal an der Tür anklopfen", new NamespacedKey(namespace, "single"));
|
||||
public static Options.Option knockThreeTimes = new Options.Option("Dreimal an der Tür anklopfen", new NamespacedKey(namespace, "three"));
|
||||
|
||||
public KnockDoorSetting() {
|
||||
super(
|
||||
Settings.Key.KnockDoors,
|
||||
new Options(List.of(disabled, knockSingleTime, knockThreeTimes))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SettingCategory category() {
|
||||
return SettingCategory.Gameplay;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String title() {
|
||||
return "Klopfen an Türen";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String description() {
|
||||
return "Klopft durch das schlagen an eine Tür an.";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Material icon() {
|
||||
return Material.BELL;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Options.Option defaultValue() {
|
||||
return disabled;
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.maintenance;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||
import eu.mhsl.craftattack.spawn.config.Configuration;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Maintenance extends Appliance {
|
||||
private boolean isInMaintenance;
|
||||
private final String configKey = "enabled";
|
||||
|
||||
public Maintenance() {
|
||||
super("maintenance");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
this.isInMaintenance = localConfig().getBoolean(configKey, false);
|
||||
}
|
||||
|
||||
public void setState(boolean enabled) {
|
||||
this.isInMaintenance = enabled;
|
||||
localConfig().set(configKey, enabled);
|
||||
Configuration.saveChanges();
|
||||
}
|
||||
|
||||
public boolean isInMaintenance() {
|
||||
return isInMaintenance;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<ApplianceCommand<?>> commands() {
|
||||
return List.of(new MaintenanceCommand());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<Listener> listeners() {
|
||||
return List.of(new PreventMaintenanceJoinListener());
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.maintenance;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class MaintenanceCommand extends ApplianceCommand<Maintenance> {
|
||||
Map<String, Boolean> arguments = Map.of("enable", true, "disable", false);
|
||||
|
||||
public MaintenanceCommand() {
|
||||
super("maintanance");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
|
||||
if(args.length != 1 || !arguments.containsKey(args[0])) throw new Error("Argument 'enable' oder 'disable' gefordert!");
|
||||
getAppliance().setState(arguments.get(args[0]));
|
||||
sender.sendMessage(String.format("Maintanance: %b", getAppliance().isInMaintenance()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||
return arguments.keySet().stream().toList();
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.maintenance;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||
import eu.mhsl.craftattack.spawn.util.text.DisconnectInfo;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.player.PlayerLoginEvent;
|
||||
|
||||
public class PreventMaintenanceJoinListener extends ApplianceListener<Maintenance> {
|
||||
@EventHandler
|
||||
public void onJoin(PlayerLoginEvent event) {
|
||||
if(!getAppliance().isInMaintenance()) return;
|
||||
if(event.getPlayer().hasPermission("bypassMaintainance")) return;
|
||||
|
||||
DisconnectInfo disconnectInfo = new DisconnectInfo(
|
||||
"Wartunsarbeiten",
|
||||
"Zurzeit können nur Admins dem Server beitreten!",
|
||||
"Bitte warte bis die Warungsarbeiten wieder deaktiviert werden.",
|
||||
event.getPlayer().getUniqueId()
|
||||
);
|
||||
|
||||
event.disallow(PlayerLoginEvent.Result.KICK_OTHER, disconnectInfo.getComponent());
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.optionLinks;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.Main;
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ServerLinks;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
public class OptionLinks extends Appliance {
|
||||
record ComponentSupplier() {}
|
||||
record UriSupplier(Player player) {}
|
||||
record UriConsumer(String uri) {}
|
||||
record SuppliedLink(Function<ComponentSupplier, Component> component, Function<UriSupplier, UriConsumer> uri) {}
|
||||
|
||||
List<SuppliedLink> links = List.of(
|
||||
new SuppliedLink(
|
||||
componentSupplier -> Component.text("CraftAttack Homepage", NamedTextColor.GOLD),
|
||||
uriSupplier -> new UriConsumer("https://mhsl.eu/craftattack")
|
||||
),
|
||||
new SuppliedLink(
|
||||
componentSupplier -> Component.text("Regeln", NamedTextColor.GOLD),
|
||||
uriSupplier -> new UriConsumer("https://mhsl.eu/craftattack/rules")
|
||||
)
|
||||
);
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
Bukkit.getServer().getServerLinks().getLinks()
|
||||
.forEach(serverLink -> Bukkit.getServer().getServerLinks().removeLink(serverLink));
|
||||
}
|
||||
|
||||
public void setServerLinks(Player player) {
|
||||
ServerLinks playerLinks = Bukkit.getServerLinks().copy();
|
||||
Bukkit.getScheduler().runTaskAsynchronously(Main.instance(), () -> {
|
||||
this.links.forEach(suppliedLink -> {
|
||||
Component component = suppliedLink.component.apply(new ComponentSupplier());
|
||||
String uri = suppliedLink.uri.apply(new UriSupplier(player)).uri;
|
||||
|
||||
try {
|
||||
playerLinks.addLink(component, URI.create(uri));
|
||||
} catch(IllegalArgumentException e) {
|
||||
Main.logger().log(Level.INFO, String.format("Failed to create OptionLink '%s' for player '%s'", uri, player.getName()), e);
|
||||
}
|
||||
});
|
||||
player.sendLinks(playerLinks);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<Listener> listeners() {
|
||||
return List.of(new UpdateLinksListener());
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.optionLinks;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
|
||||
public class UpdateLinksListener extends ApplianceListener<OptionLinks> {
|
||||
@EventHandler
|
||||
public void onJoin(PlayerJoinEvent event) {
|
||||
getAppliance().setServerLinks(event.getPlayer());
|
||||
}
|
||||
}
|
@ -38,7 +38,7 @@ public class Outlawed extends Appliance {
|
||||
if(!player.isOnline()) return;
|
||||
if(status != Status.FORCED) return;
|
||||
try {
|
||||
Main.instance().getAppliance(Whitelist.class).integrityCheck(player);
|
||||
queryAppliance(Whitelist.class).integrityCheck(player);
|
||||
} catch(DisconnectInfo.Throwable e) {
|
||||
Bukkit.getScheduler().runTask(Main.instance(), () -> e.getDisconnectScreen().applyKick(player));
|
||||
}
|
||||
@ -75,7 +75,7 @@ public class Outlawed extends Appliance {
|
||||
|
||||
private void setLawStatus(Player player, Status status) {
|
||||
playerStatusMap.put(player, status);
|
||||
Main.instance().getAppliance(DisplayName.class).update(player);
|
||||
queryAppliance(DisplayName.class).update(player);
|
||||
|
||||
List<String> newList = localConfig().getStringList(voluntarilyEntry);
|
||||
if(status.equals(Status.VOLUNTARILY)) {
|
||||
@ -93,7 +93,7 @@ public class Outlawed extends Appliance {
|
||||
}
|
||||
|
||||
private boolean isTimeout(Player player) {
|
||||
return timeouts.get(player.getUniqueId()) < System.currentTimeMillis() - timeoutInMs;
|
||||
return timeouts.getOrDefault(player.getUniqueId(), 0L) > System.currentTimeMillis() - timeoutInMs;
|
||||
}
|
||||
|
||||
private void setTimeout(Player player) {
|
||||
@ -127,7 +127,7 @@ public class Outlawed extends Appliance {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected List<Listener> eventHandlers() {
|
||||
protected List<Listener> listeners() {
|
||||
return List.of(new OutlawedReminderListener());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.packSelect;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ChangePackCommand extends ApplianceCommand.PlayerChecked<PackSelect> {
|
||||
public static final String commandName = "texturepack";
|
||||
public ChangePackCommand() {
|
||||
super(commandName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
|
||||
getAppliance().openPackInventory(getPlayer());
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.packSelect;
|
||||
|
||||
import com.google.gson.*;
|
||||
import eu.mhsl.craftattack.spawn.appliance.CachedApplianceSupplier;
|
||||
import eu.mhsl.craftattack.spawn.util.inventory.HeadBuilder;
|
||||
import eu.mhsl.craftattack.spawn.util.text.ComponentUtil;
|
||||
import net.kyori.adventure.resource.ResourcePackInfo;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class PackConfiguration extends CachedApplianceSupplier<PackSelect> {
|
||||
public record Pack(UUID id, String name, String description, String author, ResourcePackInfo info, String icon) {
|
||||
public ItemStack buildItem() {
|
||||
ItemStack stack = HeadBuilder.getCustomTextureHead(icon);
|
||||
ItemMeta meta = stack.getItemMeta();
|
||||
meta.itemName(Component.text(id.toString()));
|
||||
meta.displayName(Component.text(name(), NamedTextColor.GOLD));
|
||||
List<Component> lore = new ArrayList<>();
|
||||
lore.add(Component.text("Autor: ", NamedTextColor.DARK_GRAY).append(Component.text(author)));
|
||||
lore.add(Component.text(" "));
|
||||
lore.addAll(
|
||||
ComponentUtil.lineBreak(description())
|
||||
.map(s -> Component.text(s, NamedTextColor.GRAY))
|
||||
.toList()
|
||||
);
|
||||
lore.add(Component.text(" "));
|
||||
meta.lore(lore);
|
||||
stack.setItemMeta(meta);
|
||||
return stack;
|
||||
}
|
||||
|
||||
public boolean equalsItem(ItemStack other) {
|
||||
String itemName = PlainTextComponentSerializer.plainText().serialize(other.getItemMeta().itemName());
|
||||
try {
|
||||
return UUID.fromString(itemName).equals(id);
|
||||
} catch(IllegalArgumentException ignored) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
public record PackList(List<Pack> packs) {
|
||||
public Optional<Pack> findFromItem(ItemStack itemStack) {
|
||||
return packs.stream()
|
||||
.filter(pack -> pack.equalsItem(itemStack))
|
||||
.findFirst();
|
||||
}
|
||||
}
|
||||
public record SerializedPackList(List<UUID> packs) {}
|
||||
|
||||
private final PackList packList;
|
||||
private final Gson gson = new GsonBuilder().create();
|
||||
|
||||
private PackConfiguration() {
|
||||
this.packList = new PackList(new ArrayList<>());
|
||||
}
|
||||
|
||||
private PackConfiguration(String data) {
|
||||
SerializedPackList serializedData = gson.fromJson(data, SerializedPackList.class);
|
||||
|
||||
var availablePackMap = getAppliance().availablePacks.packs().stream()
|
||||
.collect(Collectors.toMap(PackConfiguration.Pack::id, pack -> pack));
|
||||
|
||||
this.packList = new PackList(
|
||||
serializedData.packs().stream()
|
||||
.map(availablePackMap::get)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
|
||||
if (this.packList.packs().isEmpty()) throw new IllegalArgumentException("Serialized data does not contain any valid data!");
|
||||
}
|
||||
|
||||
public static PackConfiguration deserialize(String data) {
|
||||
return new PackConfiguration(data);
|
||||
}
|
||||
|
||||
public static PackConfiguration empty() {
|
||||
return new PackConfiguration();
|
||||
}
|
||||
|
||||
public String serialize() {
|
||||
return gson.toJson(new SerializedPackList(this.packList.packs().stream().map(Pack::id).toList()));
|
||||
}
|
||||
|
||||
public List<Pack> getPackList() {
|
||||
return packList.packs();
|
||||
}
|
||||
}
|
@ -0,0 +1,171 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.packSelect;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.Main;
|
||||
import eu.mhsl.craftattack.spawn.appliance.CachedApplianceSupplier;
|
||||
import eu.mhsl.craftattack.spawn.util.IteratorUtil;
|
||||
import eu.mhsl.craftattack.spawn.util.inventory.ItemBuilder;
|
||||
import eu.mhsl.craftattack.spawn.util.inventory.PlaceholderItems;
|
||||
import eu.mhsl.craftattack.spawn.util.world.InteractSounds;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class PackConfigurationInventory extends CachedApplianceSupplier<PackSelect> {
|
||||
private final PackConfiguration packConfiguration;
|
||||
private final Player inventoryOwner;
|
||||
private final Inventory inventory;
|
||||
|
||||
private final ItemStack reset = ItemBuilder.of(Material.BARRIER)
|
||||
.displayName(Component.text("Zurücksetzen", NamedTextColor.RED))
|
||||
.lore("Alle gewählten Texturepacks werden entfernt")
|
||||
.build();
|
||||
|
||||
private final ItemStack info = ItemBuilder.of(Material.OAK_HANGING_SIGN)
|
||||
.displayName(Component.text("Texturepacks", NamedTextColor.GOLD))
|
||||
.lore(
|
||||
"Wähle aus der oberen Liste eine oder mehrere Texturepacks aus. " +
|
||||
"Ändere die anzuwendende Reihenfolge durch Links/Rechtsklick in der unteren Liste. " +
|
||||
"Klicke auf Speichern um die Änderungen anzuwenden!"
|
||||
)
|
||||
.build();
|
||||
|
||||
private final ItemStack save = ItemBuilder.of(Material.GREEN_WOOL)
|
||||
.displayName(Component.text("Anwenden", NamedTextColor.GREEN))
|
||||
.lore("Die Ausgewählten Texturepacks werden in der entsprechenden Reihenfolge angewandt. Das Anwenden kann durch den Download je nach Internetgeschwindigkeit eine Weile dauern.")
|
||||
.build();
|
||||
|
||||
private final ItemStack unusedSlot = ItemBuilder.of(Material.LIME_STAINED_GLASS_PANE)
|
||||
.displayName(Component.text("Freier Slot", NamedTextColor.GREEN))
|
||||
.lore("Klicke auf ein Texturepack um es hinzuzufügen.")
|
||||
.build();
|
||||
|
||||
|
||||
public PackConfigurationInventory(PackConfiguration packConfiguration, Player inventoryOwner) {
|
||||
this.packConfiguration = packConfiguration;
|
||||
this.inventoryOwner = inventoryOwner;
|
||||
this.inventory = Bukkit.createInventory(null, 9 * 6, Component.text("Texturepacks"));
|
||||
this.draw();
|
||||
}
|
||||
|
||||
public Inventory getInventory() {
|
||||
return inventory;
|
||||
}
|
||||
|
||||
public void handleClick(@Nullable ItemStack clickedItem, int slot, ClickType clickType) {
|
||||
if(clickedItem == null) return;
|
||||
if(clickedItem.equals(reset)) reset();
|
||||
if(clickedItem.equals(save)) apply();
|
||||
|
||||
if(slot >= 9 && slot < 9 * 4) {
|
||||
getAppliance().availablePacks.findFromItem(clickedItem)
|
||||
.ifPresent(this::toggle);
|
||||
}
|
||||
|
||||
if(slot >= 9 * 5) {
|
||||
getAppliance().availablePacks.findFromItem(clickedItem)
|
||||
.ifPresent(pack -> {
|
||||
switch(clickType) {
|
||||
case RIGHT -> move(pack, true);
|
||||
case LEFT -> move(pack, false);
|
||||
case MIDDLE -> toggle(pack);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void move(PackConfiguration.Pack pack, boolean moveToRight) {
|
||||
List<PackConfiguration.Pack> packs = packConfiguration.getPackList();
|
||||
int index = packs.indexOf(pack);
|
||||
|
||||
if (index != -1) {
|
||||
int newIndex = moveToRight ? index + 1 : index - 1;
|
||||
if (newIndex >= 0 && newIndex < packs.size()) Collections.swap(packs, index, newIndex);
|
||||
}
|
||||
|
||||
InteractSounds.of(inventoryOwner).click();
|
||||
draw();
|
||||
}
|
||||
|
||||
private void toggle(PackConfiguration.Pack pack) {
|
||||
if(packConfiguration.getPackList().contains(pack)) {
|
||||
packConfiguration.getPackList().remove(pack);
|
||||
} else {
|
||||
packConfiguration.getPackList().add(pack);
|
||||
}
|
||||
|
||||
InteractSounds.of(inventoryOwner).click();
|
||||
draw();
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
packConfiguration.getPackList().clear();
|
||||
InteractSounds.of(inventoryOwner).delete();
|
||||
draw();
|
||||
}
|
||||
|
||||
private void apply() {
|
||||
inventoryOwner.closeInventory();
|
||||
InteractSounds.of(inventoryOwner).success();
|
||||
Bukkit.getScheduler().runTask(Main.instance(), () -> getAppliance().setPack(inventoryOwner, packConfiguration));
|
||||
}
|
||||
|
||||
private void draw() {
|
||||
inventory.clear();
|
||||
|
||||
inventory.setItem(0, packConfiguration.getPackList().isEmpty() ? PlaceholderItems.grayStainedGlassPane : reset);
|
||||
IteratorUtil.times(3, () -> inventory.addItem(PlaceholderItems.grayStainedGlassPane));
|
||||
inventory.setItem(4, info);
|
||||
IteratorUtil.times(3, () -> inventory.addItem(PlaceholderItems.grayStainedGlassPane));
|
||||
inventory.setItem(8, save);
|
||||
|
||||
IteratorUtil.iterateListInGlobal(
|
||||
9,
|
||||
getAppliance().availablePacks.packs().stream()
|
||||
.filter(pack -> !packConfiguration.getPackList().contains(pack))
|
||||
.limit(9 * 3)
|
||||
.map(pack -> {
|
||||
ItemBuilder stack = ItemBuilder.of(pack.buildItem());
|
||||
if(packConfiguration.getPackList().contains(pack)) stack.glint();
|
||||
return stack.build();
|
||||
})
|
||||
.toList(),
|
||||
inventory::setItem
|
||||
);
|
||||
|
||||
IntStream.range(9 * 4, 9 * 5)
|
||||
.forEach(slot -> inventory.setItem(slot, PlaceholderItems.grayStainedGlassPane));
|
||||
|
||||
IteratorUtil.iterateListInGlobal(
|
||||
9 * 5,
|
||||
IteratorUtil.expandList(
|
||||
IntStream.range(0, Math.min(packConfiguration.getPackList().size(), 9))
|
||||
.mapToObj(i -> {
|
||||
PackConfiguration.Pack pack = packConfiguration.getPackList().get(i);
|
||||
ItemBuilder builder = ItemBuilder.of(pack.buildItem());
|
||||
|
||||
builder
|
||||
.displayName(existing -> Component.text(String.format("#%s ", i + 1), NamedTextColor.LIGHT_PURPLE).append(existing))
|
||||
.appendLore(Component.text("➡ Rechtsklick um nach Rechts zu verschieben", NamedTextColor.AQUA))
|
||||
.appendLore(Component.text("⬅ Linksklick um nach Links zu verschieben", NamedTextColor.AQUA))
|
||||
.appendLore(Component.text("\uD83D\uDDD1 Mausradklick um zu entfernen", NamedTextColor.AQUA));
|
||||
return builder.build();
|
||||
})
|
||||
.toList(),
|
||||
9,
|
||||
unusedSlot
|
||||
),
|
||||
inventory::setItem
|
||||
);
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.packSelect;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.Main;
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||
import eu.mhsl.craftattack.spawn.appliances.packSelect.listeners.ClosePackInventoryListener;
|
||||
import eu.mhsl.craftattack.spawn.appliances.packSelect.listeners.ClickPackInventoryListener;
|
||||
import eu.mhsl.craftattack.spawn.appliances.packSelect.listeners.SetPacksOnJoinListener;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.Settings;
|
||||
import net.kyori.adventure.resource.ResourcePackInfo;
|
||||
import net.kyori.adventure.resource.ResourcePackRequest;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.*;
|
||||
|
||||
public class PackSelect extends Appliance {
|
||||
private static final NamespacedKey packKey = new NamespacedKey(Main.instance(), PackSelect.class.getName().toLowerCase(Locale.ROOT));
|
||||
|
||||
public final PackConfiguration.PackList availablePacks = new PackConfiguration.PackList(new ArrayList<>());
|
||||
public final Map<Player, PackConfigurationInventory> openInventories = new WeakHashMap<>();
|
||||
|
||||
public PackSelect() {
|
||||
super("packselect");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
Settings.instance().declareSetting(PackSelectSetting.class);
|
||||
|
||||
List<Map<?, ?>> packs = localConfig().getMapList("packs");
|
||||
Bukkit.getScheduler().runTaskAsynchronously(
|
||||
Main.instance(),
|
||||
() -> packs.stream()
|
||||
.flatMap(pack -> pack.entrySet().stream())
|
||||
.forEach(pack -> {
|
||||
@SuppressWarnings("unchecked") Map<String, String> packData = (Map<String, String>) pack.getValue();
|
||||
|
||||
try {
|
||||
ResourcePackInfo resourcePackInfo = ResourcePackInfoFactory
|
||||
.createResourcePackInfo(URI.create(packData.get("url")), packData.get("hash"))
|
||||
.join();
|
||||
|
||||
PackConfiguration.Pack packToAdd = new PackConfiguration.Pack(
|
||||
UUID.nameUUIDFromBytes(pack.getKey().toString().getBytes()),
|
||||
packData.get("name"),
|
||||
packData.get("description"),
|
||||
packData.get("author"),
|
||||
resourcePackInfo,
|
||||
packData.get("icon")
|
||||
);
|
||||
availablePacks.packs().add(packToAdd);
|
||||
} catch (Exception e) {
|
||||
Main.logger().warning(String.format("Failed to add pack %s: %s", packData.get("name"), e.getMessage()));
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public PackConfiguration getPackConfigurationForPlayer(Player player) {
|
||||
PersistentDataContainer persistentDataContainer = player.getPersistentDataContainer();
|
||||
try {
|
||||
String serialized = persistentDataContainer.get(packKey, PersistentDataType.STRING);
|
||||
Objects.requireNonNull(serialized);
|
||||
return PackConfiguration.deserialize(serialized);
|
||||
} catch(IllegalArgumentException | NullPointerException exception) {
|
||||
return PackConfiguration.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public void openPackInventory(Player player) {
|
||||
PackConfigurationInventory packInventory = new PackConfigurationInventory(getPackConfigurationForPlayer(player), player);
|
||||
player.openInventory(packInventory.getInventory());
|
||||
openInventories.put(player, packInventory);
|
||||
}
|
||||
|
||||
public void setPack(Player player, PackConfiguration packConfiguration) {
|
||||
player.getPersistentDataContainer().set(packKey, PersistentDataType.STRING, packConfiguration.serialize());
|
||||
|
||||
int packCount = packConfiguration.getPackList().size();
|
||||
if(packCount > 0) {
|
||||
player.sendMessage(
|
||||
Component.text(
|
||||
String.format("%s heruntergeladen und hinzugefügt...", packCount > 1 ? "Texturenpakete werden" : "Texturenpaket wird"),
|
||||
NamedTextColor.DARK_GREEN
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
player.sendResourcePacks(
|
||||
ResourcePackRequest.resourcePackRequest()
|
||||
.packs(
|
||||
packConfiguration.getPackList().stream()
|
||||
.map(PackConfiguration.Pack::info)
|
||||
.toList()
|
||||
.reversed()
|
||||
)
|
||||
.replace(true)
|
||||
.required(true)
|
||||
.prompt(
|
||||
Component.text()
|
||||
.append(Component.text("Bestätige um fortzufahren! Du kannst deine Entscheidung jederzeit mit ", NamedTextColor.GRAY))
|
||||
.append(Component.text(String.format("/%s ", ChangePackCommand.commandName), NamedTextColor.GOLD))
|
||||
.append(Component.text("ändern.", NamedTextColor.GRAY))
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
public boolean isNotPackInventory(Player player, Inventory inventory) {
|
||||
PackConfigurationInventory packConfigurationInventory = this.openInventories.get(player);
|
||||
if(packConfigurationInventory == null) return true;
|
||||
return packConfigurationInventory.getInventory() != inventory;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<ApplianceCommand<?>> commands() {
|
||||
return List.of(new ChangePackCommand());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<Listener> listeners() {
|
||||
return List.of(
|
||||
new ClosePackInventoryListener(),
|
||||
new ClickPackInventoryListener(),
|
||||
new SetPacksOnJoinListener()
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.packSelect;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.Main;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.CategorizedSetting;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.SettingCategory;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.datatypes.ActionSetting;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
|
||||
public class PackSelectSetting extends ActionSetting implements CategorizedSetting {
|
||||
@Override
|
||||
protected String title() {
|
||||
return "Texturepacks";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String description() {
|
||||
return "Stelle dein persönliches Texturepack aus einer kuratierten Auswahl zusammen und gestalte deine Spielerfahrung individuell.";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Material icon() {
|
||||
return Material.PAINTING;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAction(Player player, ClickType clickType) {
|
||||
Main.instance().getAppliance(PackSelect.class).openPackInventory(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SettingCategory category() {
|
||||
return SettingCategory.Visuals;
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.packSelect;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.Main;
|
||||
import net.kyori.adventure.resource.ResourcePackInfo;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class ResourcePackInfoFactory {
|
||||
|
||||
private static boolean isValidHash(@Nullable String hash) {
|
||||
return hash != null && hash.length() == 40;
|
||||
}
|
||||
|
||||
public static @NotNull CompletableFuture<ResourcePackInfo> createResourcePackInfo(@NotNull URI resourcePackUrl, @Nullable String hash) {
|
||||
if (isValidHash(hash)) {
|
||||
return CompletableFuture.completedFuture(
|
||||
ResourcePackInfo.resourcePackInfo(UUID.nameUUIDFromBytes(hash.getBytes()), resourcePackUrl, hash)
|
||||
);
|
||||
}
|
||||
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
Main.logger().info(String.format("Start calculating SHA1 Hash of %s", resourcePackUrl));
|
||||
HttpURLConnection connection = (HttpURLConnection) resourcePackUrl.toURL().openConnection();
|
||||
connection.setRequestMethod("GET");
|
||||
connection.connect();
|
||||
|
||||
try (InputStream inputStream = connection.getInputStream()) {
|
||||
MessageDigest sha1Digest = MessageDigest.getInstance("SHA-1");
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytesRead;
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
sha1Digest.update(buffer, 0, bytesRead);
|
||||
}
|
||||
String sha1Hex = bytesToHex(sha1Digest.digest());
|
||||
|
||||
Main.logger().info(String.format("Calculating SHA1 Hash of %s completed: %s", resourcePackUrl, sha1Hex));
|
||||
return ResourcePackInfo.resourcePackInfo(UUID.nameUUIDFromBytes(sha1Hex.getBytes()), resourcePackUrl, sha1Hex);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
String error = String.format("Error whilst SHA1 calculation of %s: %s", resourcePackUrl, e.getMessage());
|
||||
Main.logger().warning(error);
|
||||
throw new RuntimeException(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static String bytesToHex(byte[] bytes) {
|
||||
StringBuilder hexString = new StringBuilder(bytes.length * 2);
|
||||
for (byte b : bytes) {
|
||||
hexString.append(String.format("%02x", b));
|
||||
}
|
||||
return hexString.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.packSelect.listeners;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||
import eu.mhsl.craftattack.spawn.appliances.packSelect.PackSelect;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
|
||||
public class ClickPackInventoryListener extends ApplianceListener<PackSelect> {
|
||||
@EventHandler
|
||||
public void interact(InventoryClickEvent event) {
|
||||
if(!(event.getWhoClicked() instanceof Player player)) return;
|
||||
if(getAppliance().isNotPackInventory(player, event.getInventory())) return;
|
||||
event.setCancelled(true);
|
||||
|
||||
getAppliance().openInventories.get(player).handleClick(
|
||||
event.getCurrentItem(),
|
||||
event.getSlot(),
|
||||
event.getClick()
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.packSelect.listeners;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||
import eu.mhsl.craftattack.spawn.appliances.packSelect.PackSelect;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
|
||||
public class ClosePackInventoryListener extends ApplianceListener<PackSelect> {
|
||||
@EventHandler
|
||||
public void onClose(InventoryCloseEvent event) {
|
||||
if(!(event.getPlayer() instanceof Player player)) return;
|
||||
if(getAppliance().isNotPackInventory(player, event.getInventory())) return;
|
||||
getAppliance().openInventories.remove(player);
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.packSelect.listeners;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.Main;
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||
import eu.mhsl.craftattack.spawn.appliances.packSelect.PackSelect;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
|
||||
public class SetPacksOnJoinListener extends ApplianceListener<PackSelect> {
|
||||
@EventHandler
|
||||
public void onJoin(PlayerJoinEvent event) {
|
||||
Bukkit.getScheduler().runTask(
|
||||
Main.instance(),
|
||||
() -> getAppliance().setPack(event.getPlayer(), getAppliance().getPackConfigurationForPlayer(event.getPlayer()))
|
||||
);
|
||||
}
|
||||
}
|
@ -50,7 +50,7 @@ public class PanicBan extends Appliance {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected List<Listener> eventHandlers() {
|
||||
protected List<Listener> listeners() {
|
||||
return List.of(new PanicBanJoinListener());
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ public class PlayerLimit extends Appliance {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected List<Listener> eventHandlers() {
|
||||
protected List<Listener> listeners() {
|
||||
return List.of(
|
||||
new PlayerLimiterListener()
|
||||
);
|
||||
|
@ -3,11 +3,13 @@ package eu.mhsl.craftattack.spawn.appliances.portableCrafting;
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
|
||||
public class OnCraftingTableUseListener extends ApplianceListener<PortableCrafting> {
|
||||
@EventHandler
|
||||
public void inInteract(PlayerInteractEvent event) {
|
||||
if(!event.getAction().equals(Action.RIGHT_CLICK_AIR)) return;
|
||||
if(!event.getMaterial().equals(Material.CRAFTING_TABLE)) return;
|
||||
getAppliance().openFor(event.getPlayer());
|
||||
}
|
||||
|
@ -9,13 +9,18 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
public class PortableCrafting extends Appliance {
|
||||
@Override
|
||||
public void onEnable() {
|
||||
Settings.instance().declareSetting(PortableCraftingSetting.class);
|
||||
}
|
||||
|
||||
public void openFor(Player player) {
|
||||
if(!Settings.instance().getSetting(player, Settings.Key.EnablePortableCrafting, Boolean.class)) return;
|
||||
player.openWorkbench(null, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<Listener> eventHandlers() {
|
||||
protected @NotNull List<Listener> listeners() {
|
||||
return List.of(new OnCraftingTableUseListener());
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.settings.settings;
|
||||
package eu.mhsl.craftattack.spawn.appliances.portableCrafting;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.CategorizedSetting;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.SettingCategory;
|
@ -175,7 +175,7 @@ public class ProjectStart extends Appliance {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected List<Listener> eventHandlers() {
|
||||
protected List<Listener> listeners() {
|
||||
return List.of(
|
||||
new PlayerInvincibleListener(),
|
||||
new NoAdvancementsListener()
|
||||
|
@ -2,6 +2,6 @@ package eu.mhsl.craftattack.spawn.appliances.settings;
|
||||
|
||||
public enum SettingCategory {
|
||||
Gameplay,
|
||||
Chat,
|
||||
Visuals,
|
||||
Misc,
|
||||
}
|
||||
|
@ -1,12 +1,10 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.settings;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.Main;
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.datatypes.Setting;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.listeners.OpenSettingsShortcutListener;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.listeners.SettingsInventoryListener;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.settings.*;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -14,13 +12,14 @@ import org.bukkit.event.Listener;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.WeakHashMap;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Settings extends Appliance {
|
||||
private static Settings settingsInstance;
|
||||
private final Set<Class<? extends Setting<?>>> declaredSettings = new HashSet<>();
|
||||
|
||||
public enum Key {
|
||||
TechnicalTab,
|
||||
@ -31,13 +30,24 @@ public class Settings extends Appliance {
|
||||
SignEdit,
|
||||
HotbarReplacer,
|
||||
ChatMentions,
|
||||
DoubleDoors,
|
||||
KnockDoors,
|
||||
}
|
||||
|
||||
public static Settings instance() {
|
||||
if(settingsInstance != null) return settingsInstance;
|
||||
Settings instance = Main.instance().getAppliance(Settings.class);
|
||||
Settings.settingsInstance = instance;
|
||||
return instance;
|
||||
Settings.settingsInstance = queryAppliance(Settings.class);
|
||||
return settingsInstance;
|
||||
}
|
||||
|
||||
public void declareSetting(Class<? extends Setting<?>> setting) {
|
||||
this.declaredSettings.add(setting);
|
||||
this.settingsCache.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
Settings.instance().declareSetting(SettingsShortcutSetting.class);
|
||||
}
|
||||
|
||||
public record OpenSettingsInventory(Inventory inventory, List<Setting<?>> settings) {
|
||||
@ -49,25 +59,31 @@ public class Settings extends Appliance {
|
||||
private List<Setting<?>> getSettings(Player player) {
|
||||
if(settingsCache.containsKey(player)) return settingsCache.get(player);
|
||||
|
||||
List<Setting<?>> settings = List.of(
|
||||
new PortableCraftingSetting(),
|
||||
new AutoShulkerSetting(),
|
||||
new SignEditSetting(),
|
||||
new HotbarReplaceSetting(),
|
||||
new ChatMentionSetting(),
|
||||
new ShowJoinAndLeaveMessagesSetting(),
|
||||
new TechnicalTablistSetting(),
|
||||
new SettingsShortcutSetting()
|
||||
);
|
||||
List<Setting<?>> settings = this.declaredSettings.stream()
|
||||
.map(clazz -> {
|
||||
try {
|
||||
return clazz.getDeclaredConstructor();
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(String.format("Setting '%s' does not have an accessible constructor", clazz.getName()), e);
|
||||
}
|
||||
})
|
||||
.map(constructor -> {
|
||||
try {
|
||||
return constructor.newInstance();
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException(String.format("Failed to create instance of setting '%s'", constructor.getDeclaringClass().getName()), e);
|
||||
}
|
||||
})
|
||||
.peek(setting -> setting.initializeFromPlayer(player))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
settings.forEach(setting -> setting.initializeFromPlayer(player));
|
||||
this.settingsCache.put(player, settings);
|
||||
return settings;
|
||||
}
|
||||
|
||||
public <T> T getSetting(Player player, Key key, Class<T> clazz) {
|
||||
Setting<?> setting = getSettings(player).stream()
|
||||
.filter(s -> s.getKey().equals(key))
|
||||
.filter(s -> Objects.equals(s.getKey(), key))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
|
||||
@ -119,11 +135,15 @@ public class Settings extends Appliance {
|
||||
}
|
||||
|
||||
private int calculateInvSize(List<Setting<?>> settings) {
|
||||
int countOfUncategorized = (int) settings.stream().filter(setting -> !(setting instanceof CategorizedSetting)).count();
|
||||
int countOfUncategorized = (int) settings.stream()
|
||||
.filter(setting -> !(setting instanceof CategorizedSetting))
|
||||
.count();
|
||||
|
||||
return Arrays.stream(SettingCategory.values())
|
||||
.map(settingCategory -> settings.stream()
|
||||
.filter(setting -> setting instanceof CategorizedSetting)
|
||||
.filter(setting -> ((CategorizedSetting) setting).category().equals(settingCategory))
|
||||
.map(setting -> (CategorizedSetting) setting)
|
||||
.filter(categorizedSetting -> categorizedSetting.category().equals(settingCategory))
|
||||
.count())
|
||||
.map(itemCount -> itemCount + countOfUncategorized)
|
||||
.map(itemCount -> (int) Math.ceil((double) itemCount / 9))
|
||||
@ -148,7 +168,7 @@ public class Settings extends Appliance {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected List<Listener> eventHandlers() {
|
||||
protected List<Listener> listeners() {
|
||||
return List.of(
|
||||
new SettingsInventoryListener(),
|
||||
new OpenSettingsShortcutListener()
|
||||
|
@ -1,8 +1,5 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.settings.settings;
|
||||
package eu.mhsl.craftattack.spawn.appliances.settings;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.CategorizedSetting;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.SettingCategory;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.Settings;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.datatypes.BoolSetting;
|
||||
import org.bukkit.Material;
|
||||
|
@ -0,0 +1,50 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.settings.datatypes;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
public abstract class ActionSetting extends Setting<Void> {
|
||||
public ActionSetting() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
protected abstract void onAction(Player player, ClickType clickType);
|
||||
|
||||
@Override
|
||||
public ItemMeta buildMeta(ItemMeta meta) {
|
||||
meta.displayName(Component.text(title(), NamedTextColor.WHITE));
|
||||
meta.lore(buildDescription(description()));
|
||||
return meta;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void change(Player player, ClickType clickType) {
|
||||
onAction(player, clickType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void defaultValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fromStorage(PersistentDataContainer container) {}
|
||||
|
||||
@Override
|
||||
protected void toStorage(PersistentDataContainer container, Void value) {}
|
||||
|
||||
@Override
|
||||
public Class<?> dataType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void state() {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ package eu.mhsl.craftattack.spawn.appliances.settings.datatypes;
|
||||
import eu.mhsl.craftattack.spawn.appliances.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;
|
||||
@ -47,7 +48,7 @@ public abstract class BoolSetting extends Setting<Boolean> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void change(ClickType clickType) {
|
||||
protected void change(Player player, ClickType clickType) {
|
||||
this.state = !this.state;
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import com.google.gson.Gson;
|
||||
import eu.mhsl.craftattack.spawn.appliances.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;
|
||||
@ -87,7 +88,7 @@ public abstract class MultiBoolSetting<T> extends Setting<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void change(ClickType clickType) {
|
||||
protected void change(Player player, ClickType clickType) {
|
||||
var recordComponents = this.state.getClass().getRecordComponents();
|
||||
|
||||
int currentIndex = IntStream.range(0, recordComponents.length)
|
||||
|
@ -5,6 +5,7 @@ import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
@ -57,7 +58,7 @@ public abstract class SelectSetting extends Setting<SelectSetting.Options.Option
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void change(ClickType clickType) {
|
||||
protected void change(Player player, ClickType clickType) {
|
||||
int optionModifier = clickType.equals(ClickType.LEFT) ? 1 : -1;
|
||||
List<Options.Option> options = this.options.options;
|
||||
this.state = IntStream.range(0, options.size())
|
||||
|
@ -37,7 +37,7 @@ public abstract class Setting<TDataType> {
|
||||
}
|
||||
|
||||
public void triggerChange(Player p, ClickType clickType) {
|
||||
this.change(clickType);
|
||||
this.change(p, clickType);
|
||||
toStorage(p.getPersistentDataContainer(), this.state());
|
||||
}
|
||||
|
||||
@ -57,7 +57,7 @@ public abstract class Setting<TDataType> {
|
||||
protected abstract String description();
|
||||
protected abstract Material icon();
|
||||
public abstract ItemMeta buildMeta(ItemMeta meta);
|
||||
protected abstract void change(ClickType clickType);
|
||||
protected abstract void change(Player player, ClickType clickType);
|
||||
protected abstract TDataType defaultValue();
|
||||
protected abstract void fromStorage(PersistentDataContainer container);
|
||||
protected abstract void toStorage(PersistentDataContainer container, TDataType value);
|
||||
|
@ -0,0 +1,22 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.snowballKnockback;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SnowballKnockback extends Appliance {
|
||||
public void dealSnowballKnockback(LivingEntity entity, Entity snowball) {
|
||||
entity.damage(0.1);
|
||||
entity.knockback(0.4, -snowball.getVelocity().getX(), -snowball.getVelocity().getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected List<Listener> listeners() {
|
||||
return List.of(new SnowballKnockbackListener());
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.snowballKnockback;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.entity.ProjectileHitEvent;
|
||||
|
||||
public class SnowballKnockbackListener extends ApplianceListener<SnowballKnockback> {
|
||||
@EventHandler
|
||||
public void onSnowballHit(ProjectileHitEvent event) {
|
||||
if(event.getHitEntity() == null) return;
|
||||
if(!event.getEntityType().equals(EntityType.SNOWBALL)) return;
|
||||
if(!(event.getHitEntity() instanceof LivingEntity hitEntity)) return;
|
||||
|
||||
Entity snowball = event.getEntity();
|
||||
getAppliance().dealSnowballKnockback(hitEntity, snowball);
|
||||
}
|
||||
}
|
@ -16,6 +16,8 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.OperatingSystemMXBean;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
|
||||
@ -23,6 +25,7 @@ import java.util.List;
|
||||
public class Tablist extends Appliance {
|
||||
private final RainbowComponent serverName = new RainbowComponent(" CraftAttack 7 ", 7, 3);
|
||||
private NetworkMonitor networkMonitor;
|
||||
private OperatingSystemMXBean systemMonitor;
|
||||
|
||||
public Tablist() {
|
||||
super("tablist");
|
||||
@ -30,8 +33,12 @@ public class Tablist extends Appliance {
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
Settings.instance().declareSetting(TechnicalTablistSetting.class);
|
||||
|
||||
int tabRefreshRate = 3;
|
||||
this.networkMonitor = new NetworkMonitor(localConfig().getString("interface"), Duration.ofSeconds(1));
|
||||
this.systemMonitor = ManagementFactory.getOperatingSystemMXBean();
|
||||
|
||||
Bukkit.getScheduler().runTaskTimerAsynchronously(
|
||||
Main.instance(),
|
||||
() -> IteratorUtil.onlinePlayers(this::updateHeader),
|
||||
@ -63,8 +70,9 @@ public class Tablist extends Appliance {
|
||||
.append(ComponentUtil.getFormattedPing(player)).appendNewline()
|
||||
.append(ComponentUtil.getFormattedNetworkStats(
|
||||
this.networkMonitor.getTraffic(),
|
||||
this.networkMonitor.getPackets())
|
||||
).appendNewline();
|
||||
this.networkMonitor.getPackets()
|
||||
)).appendNewline()
|
||||
.append(ComponentUtil.getFormattedSystemStats(this.systemMonitor)).appendNewline();
|
||||
}
|
||||
|
||||
player.sendPlayerListHeader(header);
|
||||
@ -76,7 +84,7 @@ public class Tablist extends Appliance {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected List<Listener> eventHandlers() {
|
||||
protected List<Listener> listeners() {
|
||||
return List.of(new TablistListener());
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.settings.settings;
|
||||
package eu.mhsl.craftattack.spawn.appliances.tablist;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.CategorizedSetting;
|
||||
import eu.mhsl.craftattack.spawn.appliances.settings.SettingCategory;
|
@ -14,7 +14,7 @@ public class TitleClear extends Appliance {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected List<Listener> eventHandlers() {
|
||||
protected List<Listener> listeners() {
|
||||
return List.of(
|
||||
new TitleClearListener()
|
||||
);
|
||||
|
@ -64,7 +64,7 @@ public class Whitelist extends Appliance {
|
||||
);
|
||||
}
|
||||
|
||||
Main.instance().getAppliance(Outlawed.class).updateForcedStatus(player, timestampRelevant(user.outlawed_until));
|
||||
queryAppliance(Outlawed.class).updateForcedStatus(player, timestampRelevant(user.outlawed_until));
|
||||
|
||||
String purePlayerName = Floodgate.isBedrock(player)
|
||||
? Floodgate.getBedrockPlayer(player).getUsername()
|
||||
@ -144,7 +144,7 @@ public class Whitelist extends Appliance {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected List<Listener> eventHandlers() {
|
||||
protected List<Listener> listeners() {
|
||||
return List.of(
|
||||
new PlayerJoinListener()
|
||||
);
|
||||
|
@ -44,15 +44,13 @@ public class WorldMuseum extends Appliance {
|
||||
|
||||
public void handleVillagerInteraction(Player player) {
|
||||
if(Floodgate.isBedrock(player)) {
|
||||
Floodgate.runBedrockOnly(player, floodgatePlayer -> {
|
||||
floodgatePlayer.sendForm(
|
||||
SimpleForm.builder()
|
||||
.title("Nicht unterstützt")
|
||||
.content("Bedrock-Spieler werden derzeit für das Weltenmuseum aus Kompatiblitätsgründen nicht zugelassen! Tut uns Leid.")
|
||||
.button("Ok")
|
||||
.build()
|
||||
);
|
||||
});
|
||||
Floodgate.runBedrockOnly(player, floodgatePlayer -> floodgatePlayer.sendForm(
|
||||
SimpleForm.builder()
|
||||
.title("Nicht unterstützt")
|
||||
.content("Bedrock-Spieler werden derzeit für das Weltenmuseum aus Kompatiblitätsgründen nicht zugelassen! Tut uns Leid.")
|
||||
.button("Ok")
|
||||
.build()
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -68,7 +66,7 @@ public class WorldMuseum extends Appliance {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected List<Listener> eventHandlers() {
|
||||
protected List<Listener> listeners() {
|
||||
return List.of(
|
||||
new PlayerInteractAtEntityEventListener(this.villager.getUniqueId(), playerInteractAtEntityEvent -> handleVillagerInteraction(playerInteractAtEntityEvent.getPlayer())),
|
||||
new DismissInventoryOpenFromHolder(this.villager.getUniqueId())
|
||||
|
@ -0,0 +1,99 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.yearRank;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.Main;
|
||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
public class YearRank extends Appliance {
|
||||
record CraftAttackYear(String name) {}
|
||||
private final Map<UUID, List<CraftAttackYear>> rankMap = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
File folder = new File(Main.instance().getDataFolder(), "yearRank");
|
||||
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
folder.mkdirs();
|
||||
|
||||
Optional<File[]> dataFolders = Optional.ofNullable(folder.listFiles());
|
||||
if(dataFolders.isEmpty()) return;
|
||||
|
||||
List.of(dataFolders.get()).forEach(playerDataFolder -> {
|
||||
Optional<File[]> datFiles = Optional.ofNullable(playerDataFolder.listFiles());
|
||||
if(datFiles.isEmpty()) return;
|
||||
|
||||
CraftAttackYear craftAttackYear = new CraftAttackYear(playerDataFolder.getName());
|
||||
|
||||
Arrays.stream(datFiles.get())
|
||||
.map(file -> file.getName().split("\\.")[0])
|
||||
.distinct()
|
||||
.map(UUID::fromString)
|
||||
.peek(uuid -> rankMap.computeIfAbsent(uuid, p -> new ArrayList<>()))
|
||||
.forEach(uuid -> rankMap.get(uuid).add(craftAttackYear));
|
||||
});
|
||||
}
|
||||
|
||||
public @Nullable Component getNamePrefix(Player player) {
|
||||
if(!rankMap.containsKey(player.getUniqueId())) return null;
|
||||
int yearCount = rankMap.get(player.getUniqueId()).size();
|
||||
if(yearCount <= 3) return null;
|
||||
|
||||
return Component.text()
|
||||
.append(Component.text("[\uD83C\uDF1F]", NamedTextColor.GOLD))
|
||||
.hoverEvent(HoverEvent.showText(
|
||||
Component.text(String.format("Langzeitspieler: %s ist bereits seit %d Jahren dabei!", player.getName(), yearCount))
|
||||
))
|
||||
.build();
|
||||
}
|
||||
|
||||
public Component listYearRanks() {
|
||||
TextComponent.Builder builder = Component.text();
|
||||
builder.append(Component.text("Top 30 Spieler: ", NamedTextColor.GOLD));
|
||||
rankMap.keySet().stream()
|
||||
.map(uuid -> Map.entry(uuid, rankMap.get(uuid).size()))
|
||||
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
|
||||
.limit(30)
|
||||
.forEach(entry -> builder
|
||||
.appendNewline()
|
||||
.append(Component.text(entry.getKey().toString(), NamedTextColor.GRAY)
|
||||
.hoverEvent(HoverEvent.showText(Component.text(entry.getKey().toString())))
|
||||
.clickEvent(ClickEvent.copyToClipboard(entry.getKey().toString())))
|
||||
.append(Component.text(": "))
|
||||
.append(Component.text(entry.getValue(), NamedTextColor.GOLD)));
|
||||
|
||||
builder
|
||||
.appendNewline()
|
||||
.appendNewline()
|
||||
.append(Component.text("Übersischt:", NamedTextColor.GOLD));
|
||||
|
||||
rankMap.values().stream()
|
||||
.mapMulti(Iterable::forEach)
|
||||
.filter(o -> o instanceof CraftAttackYear)
|
||||
.map(o -> (CraftAttackYear) o)
|
||||
.distinct()
|
||||
.forEach(craftAttackYear -> builder
|
||||
.appendNewline()
|
||||
.append(Component.text(craftAttackYear.name, NamedTextColor.GRAY))
|
||||
.append(Component.text(": "))
|
||||
.append(Component.text(rankMap.keySet().stream()
|
||||
.filter(uuid -> rankMap.get(uuid).contains(craftAttackYear)).count())));
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull List<ApplianceCommand<?>> commands() {
|
||||
return List.of(new YearRankCommand());
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package eu.mhsl.craftattack.spawn.appliances.yearRank;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class YearRankCommand extends ApplianceCommand<YearRank> {
|
||||
public YearRankCommand() {
|
||||
super("yearRank");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
|
||||
sender.sendMessage(getAppliance().listYearRanks());
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package eu.mhsl.craftattack.spawn.config;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.Main;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
@ -10,9 +11,11 @@ public class Configuration {
|
||||
private static final String configName = "config.yml";
|
||||
private static final File configFile = new File(Main.instance().getDataFolder().getAbsolutePath() + "/" + configName);
|
||||
public static FileConfiguration cfg;
|
||||
public static ConfigurationSection pluginConfig;
|
||||
|
||||
public static void readConfig() {
|
||||
cfg = YamlConfiguration.loadConfiguration(configFile);
|
||||
pluginConfig = cfg.getConfigurationSection("plugin");
|
||||
}
|
||||
|
||||
public static void saveChanges() {
|
||||
|
@ -5,9 +5,14 @@ import org.bukkit.GameRule;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class IteratorUtil {
|
||||
public static void worlds(Consumer<World> world) {
|
||||
@ -25,4 +30,25 @@ public class IteratorUtil {
|
||||
public static void setGameRules(Map<GameRule<Boolean>, Boolean> rules, boolean inverse) {
|
||||
rules.forEach((gameRule, value) -> IteratorUtil.worlds(world -> world.setGameRule(gameRule, value ^ inverse)));
|
||||
}
|
||||
|
||||
public static void times(int times, Runnable callback) {
|
||||
IntStream.range(0, times).forEach(value -> callback.run());
|
||||
}
|
||||
|
||||
public static <T> void iterateListInGlobal(int sectionStart, List<T> list, BiConsumer<Integer, T> callback) {
|
||||
IntStream.range(sectionStart, sectionStart + list.size())
|
||||
.forEach(value -> callback.accept(value, list.get(value - sectionStart)));
|
||||
}
|
||||
|
||||
public static void iterateLocalInGlobal(int sectionStart, int localLength, BiConsumer<Integer, Integer> callback) {
|
||||
IntStream.range(sectionStart, sectionStart + localLength)
|
||||
.forEach(value -> callback.accept(value, value + sectionStart));
|
||||
}
|
||||
|
||||
public static <T> List<T> expandList(List<T> list, int targetSize, T defaultValue) {
|
||||
return Stream.concat(
|
||||
list.stream(),
|
||||
Stream.generate(() -> defaultValue).limit(Math.max(0, targetSize - list.size()))
|
||||
).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,22 @@
|
||||
package eu.mhsl.craftattack.spawn.util.inventory;
|
||||
|
||||
import com.destroystokyo.paper.profile.PlayerProfile;
|
||||
import com.destroystokyo.paper.profile.ProfileProperty;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class HeadBuilder {
|
||||
public static ItemStack getCustomTextureHead(String base64) {
|
||||
ItemStack head = new ItemStack(Material.PLAYER_HEAD);
|
||||
SkullMeta meta = (SkullMeta) head.getItemMeta();
|
||||
PlayerProfile profile = Bukkit.createProfile(UUID.nameUUIDFromBytes(base64.getBytes()), null);
|
||||
profile.setProperty(new ProfileProperty("textures", base64));
|
||||
meta.setPlayerProfile(profile);
|
||||
head.setItemMeta(meta);
|
||||
return head;
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
package eu.mhsl.craftattack.spawn.util.inventory;
|
||||
|
||||
import eu.mhsl.craftattack.spawn.util.text.ComponentUtil;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class ItemBuilder {
|
||||
private final ItemStack itemStack;
|
||||
|
||||
@Contract(value = "_ -> new", pure = true)
|
||||
public static @NotNull ItemBuilder of(Material material) {
|
||||
return new ItemBuilder(material);
|
||||
}
|
||||
|
||||
@Contract(value = "_ -> new", pure = true)
|
||||
public static @NotNull ItemBuilder of(ItemStack itemStack) {
|
||||
return new ItemBuilder(itemStack);
|
||||
}
|
||||
|
||||
private ItemBuilder(Material material) {
|
||||
this.itemStack = ItemStack.of(material);
|
||||
}
|
||||
|
||||
private ItemBuilder(ItemStack itemStack) {
|
||||
this.itemStack = itemStack;
|
||||
}
|
||||
|
||||
public ItemBuilder displayName(Component displayName) {
|
||||
return this.withMeta(itemMeta -> itemMeta.displayName(displayName));
|
||||
}
|
||||
|
||||
public ItemBuilder displayName(Function<Component, Component> process) {
|
||||
return this.displayName(process.apply(itemStack.displayName()));
|
||||
}
|
||||
|
||||
public ItemBuilder lore(String text) {
|
||||
return this.lore(text, 50, NamedTextColor.GRAY);
|
||||
}
|
||||
|
||||
public ItemBuilder lore(String text, NamedTextColor color) {
|
||||
return this.lore(text, 50, color);
|
||||
}
|
||||
|
||||
public ItemBuilder lore(String text, int linebreak, NamedTextColor color) {
|
||||
return this.withMeta(itemMeta -> itemMeta.lore(
|
||||
ComponentUtil.lineBreak(text, linebreak)
|
||||
.map(s -> Component.text(s, color))
|
||||
.toList()
|
||||
));
|
||||
}
|
||||
|
||||
public ItemBuilder appendLore(Component text) {
|
||||
List<Component> lore = itemStack.lore();
|
||||
Objects.requireNonNull(lore, "Cannot append lore to Item without lore");
|
||||
lore.add(text);
|
||||
return this.withMeta(itemMeta -> itemMeta.lore(lore));
|
||||
}
|
||||
|
||||
public ItemBuilder noStacking() {
|
||||
return this.withMeta(itemMeta -> itemMeta.setMaxStackSize(1));
|
||||
}
|
||||
|
||||
public ItemBuilder glint() {
|
||||
return this.withMeta(itemMeta -> itemMeta.setEnchantmentGlintOverride(true));
|
||||
}
|
||||
|
||||
public ItemBuilder amount(int amount) {
|
||||
this.itemStack.setAmount(amount);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemBuilder withMeta(Consumer<ItemMeta> callback) {
|
||||
ItemMeta meta = this.itemStack.getItemMeta();
|
||||
callback.accept(meta);
|
||||
this.itemStack.setItemMeta(meta);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemStack build() {
|
||||
return this.itemStack;
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package eu.mhsl.craftattack.spawn.util.inventory;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class PlaceholderItems {
|
||||
private static final Component emptyName = Component.text(" ");
|
||||
public static final ItemStack grayStainedGlassPane = ItemBuilder.of(Material.GRAY_STAINED_GLASS_PANE)
|
||||
.displayName(emptyName)
|
||||
.noStacking()
|
||||
.build();
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package eu.mhsl.craftattack.spawn.util.server;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.geysermc.cumulus.form.SimpleForm;
|
||||
import org.geysermc.floodgate.api.FloodgateApi;
|
||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||
|
||||
@ -24,4 +25,22 @@ public class Floodgate {
|
||||
public static void runJavaOnly(Player p, Consumer<Player> callback) {
|
||||
if(!isBedrock(p)) callback.accept(p);
|
||||
}
|
||||
|
||||
public static void throwWithMessageWhenBedrock(Player player) {
|
||||
if(isBedrock(player)) {
|
||||
SimpleForm.builder()
|
||||
.title("Nicht unterstützt")
|
||||
.content("Bedrock-Spieler werden derzeit für diese Aktion unterstützt! Tut uns Leid.")
|
||||
.button("Ok")
|
||||
.build();
|
||||
|
||||
throw new BedrockNotSupportedException(player);
|
||||
}
|
||||
}
|
||||
|
||||
public static class BedrockNotSupportedException extends RuntimeException {
|
||||
public BedrockNotSupportedException(Player player) {
|
||||
super(String.format("Bedrock player '%s' tried using an Operation which is unsupported.", player.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.awt.*;
|
||||
import java.lang.management.OperatingSystemMXBean;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@ -21,6 +22,13 @@ public class ComponentUtil {
|
||||
return Component.text().append(a.appendNewline().append(b)).build();
|
||||
}
|
||||
|
||||
public static TextComponent appendWithSpace(Component a, Component b) {
|
||||
return Component.text().append(a).append(Component.text(" ")).append(b).build();
|
||||
}
|
||||
|
||||
public static Stream<String> lineBreak(String text) {
|
||||
return lineBreak(text, 50);
|
||||
}
|
||||
public static Stream<String> lineBreak(String text, int charactersPerLine) {
|
||||
List<String> lines = new ArrayList<>();
|
||||
String[] words = text.split(" ");
|
||||
@ -46,34 +54,6 @@ public class ComponentUtil {
|
||||
return lines.collect(Collectors.joining("\n"));
|
||||
}
|
||||
|
||||
public static Component getFormattedTPS() {
|
||||
double[] tpsValues = Bukkit.getTPS();
|
||||
|
||||
double min1 = Math.min(1.0, Math.max(0.0, tpsValues[0] / 20.0));
|
||||
double min2 = Math.min(1.0, Math.max(0.0, tpsValues[1] / 20.0));
|
||||
double min3 = Math.min(1.0, Math.max(0.0, tpsValues[2] / 20.0));
|
||||
|
||||
int red1 = (int) (255 * (1.0 - min1));
|
||||
int green1 = (int) (255 * min1);
|
||||
int red2 = (int) (255 * (1.0 - min2));
|
||||
int green2 = (int) (255 * min2);
|
||||
int red3 = (int) (255 * (1.0 - min3));
|
||||
int green3 = (int) (255 * min3);
|
||||
|
||||
TextColor tpsColor1 = TextColor.color(red1, green1, 0);
|
||||
TextColor tpsColor2 = TextColor.color(red2, green2, 0);
|
||||
TextColor tpsColor3 = TextColor.color(red3, green3, 0);
|
||||
|
||||
return Component.text()
|
||||
.append(Component.text("TPS 1, 5, 15m: ", NamedTextColor.GRAY))
|
||||
.append(Component.text(String.format("%.2f", tpsValues[0]), tpsColor1))
|
||||
.append(Component.text(", "))
|
||||
.append(Component.text(String.format("%.2f", tpsValues[1]), tpsColor2))
|
||||
.append(Component.text(", "))
|
||||
.append(Component.text(String.format("%.2f", tpsValues[2]), tpsColor3))
|
||||
.build();
|
||||
}
|
||||
|
||||
public static Component getFormattedTickTimes(boolean detailed) {
|
||||
long[] times = Bukkit.getServer().getTickTimes();
|
||||
float mspt = ((float) Arrays.stream(times).sum() / times.length) * 1.0E-6f;
|
||||
@ -132,14 +112,72 @@ public class ComponentUtil {
|
||||
public static Component getFormattedNetworkStats(NetworkMonitor.Traffic traffic, NetworkMonitor.Packets packets) {
|
||||
return Component.text()
|
||||
.append(Component.text(
|
||||
DataSizeConverter.convertBytesToHumanReadable(traffic.rxBytes()) + " ↓ " + NumberAbbreviation.abbreviateNumber(packets.rxCount()) + "pps",
|
||||
DataSizeConverter.convertBytesPerSecond(traffic.rxBytes()) + " ↓ " + NumberAbbreviation.abbreviateNumber(packets.rxCount()) + "pps",
|
||||
NamedTextColor.GREEN
|
||||
))
|
||||
.append(Component.text(" | ", NamedTextColor.GRAY))
|
||||
.append(Component.text(
|
||||
DataSizeConverter.convertBytesToHumanReadable(traffic.txBytes()) + " ↑ " + NumberAbbreviation.abbreviateNumber(packets.rxCount()) + "pps",
|
||||
DataSizeConverter.convertBytesPerSecond(traffic.txBytes()) + " ↑ " + NumberAbbreviation.abbreviateNumber(packets.rxCount()) + "pps",
|
||||
NamedTextColor.RED
|
||||
))
|
||||
.build();
|
||||
}
|
||||
|
||||
public static Component getFormattedSystemStats(OperatingSystemMXBean systemMonitor) {
|
||||
if(!(systemMonitor instanceof com.sun.management.OperatingSystemMXBean monitor))
|
||||
return Component.text("Could not get System information", NamedTextColor.DARK_GRAY);
|
||||
|
||||
return Component.text()
|
||||
.append(Component.text("proc: ", NamedTextColor.GRAY))
|
||||
.append(Component.text(
|
||||
String.format("%.0f%%cpu", monitor.getProcessCpuLoad() * 100),
|
||||
NamedTextColor.GOLD
|
||||
))
|
||||
.append(Component.text(" | ", NamedTextColor.GRAY))
|
||||
.append(Component.text(
|
||||
String.format("%s time", DataSizeConverter.formatCpuTimeToHumanReadable(monitor.getProcessCpuTime())),
|
||||
NamedTextColor.LIGHT_PURPLE
|
||||
))
|
||||
.append(Component.text(" | ", NamedTextColor.GRAY))
|
||||
.append(Component.text(
|
||||
String.format(
|
||||
"%s free, %s committed RAM",
|
||||
DataSizeConverter.formatBytesToHumanReadable(monitor.getFreeMemorySize()),
|
||||
DataSizeConverter.formatBytesToHumanReadable(monitor.getCommittedVirtualMemorySize())
|
||||
),
|
||||
NamedTextColor.DARK_AQUA
|
||||
))
|
||||
.appendNewline()
|
||||
.append(Component.text("sys: ", NamedTextColor.GRAY))
|
||||
.append(Component.text(
|
||||
String.format("%.0f%%cpu", monitor.getCpuLoad() * 100),
|
||||
NamedTextColor.GOLD
|
||||
))
|
||||
.append(Component.text(" | ", NamedTextColor.GRAY))
|
||||
.append(Component.text(
|
||||
String.format(
|
||||
"1min %.2f load avg (%.0f%%)",
|
||||
monitor.getSystemLoadAverage(),
|
||||
(monitor.getSystemLoadAverage() / monitor.getAvailableProcessors()) * 100
|
||||
),
|
||||
NamedTextColor.LIGHT_PURPLE
|
||||
))
|
||||
.append(Component.text(" | ", NamedTextColor.GRAY))
|
||||
.append(Component.text(
|
||||
String.format("%s total RAM", DataSizeConverter.formatBytesToHumanReadable(monitor.getTotalMemorySize())),
|
||||
NamedTextColor.DARK_AQUA
|
||||
))
|
||||
.appendNewline()
|
||||
.append(Component.text(
|
||||
String.format(
|
||||
"%s(%s) \uD83D\uDE80 on %s with %s cpu(s)",
|
||||
monitor.getName(),
|
||||
monitor.getVersion(),
|
||||
monitor.getArch(),
|
||||
monitor.getAvailableProcessors()
|
||||
),
|
||||
NamedTextColor.GRAY
|
||||
))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package eu.mhsl.craftattack.spawn.util.text;
|
||||
|
||||
public class DataSizeConverter {
|
||||
public static String convertBytesToHumanReadable(long bytes) {
|
||||
public static String convertBytesPerSecond(long bytes) {
|
||||
double kbits = bytes * 8.0 / 1000.0;
|
||||
double mbits = kbits / 1000.0;
|
||||
|
||||
@ -11,4 +11,31 @@ public class DataSizeConverter {
|
||||
return String.format("%.2f Kbit", kbits);
|
||||
}
|
||||
}
|
||||
|
||||
public static String formatBytesToHumanReadable(long bytes) {
|
||||
String[] units = {"B", "KB", "MB", "GB", "TB", "PB", "EB"};
|
||||
int unitIndex = 0;
|
||||
double readableSize = bytes;
|
||||
|
||||
while (readableSize >= 1024 && unitIndex < units.length - 1) {
|
||||
readableSize /= 1024;
|
||||
unitIndex++;
|
||||
}
|
||||
|
||||
return String.format("%.2f%s", readableSize, units[unitIndex]);
|
||||
}
|
||||
|
||||
public static String formatCpuTimeToHumanReadable(long nanoseconds) {
|
||||
if (nanoseconds < 0) return "unsupported";
|
||||
|
||||
long seconds = nanoseconds / 1_000_000_000;
|
||||
long minutes = seconds / 60;
|
||||
long hours = minutes / 60;
|
||||
long days = hours / 24;
|
||||
|
||||
seconds %= 60;
|
||||
minutes %= 60;
|
||||
hours %= 60;
|
||||
return String.format("%dd%dh%dm%ds", days, hours, minutes, seconds);
|
||||
}
|
||||
}
|
@ -6,12 +6,12 @@ import net.kyori.adventure.text.format.TextColor;
|
||||
import java.awt.*;
|
||||
|
||||
public class RainbowComponent {
|
||||
private int hueOffset = 0;
|
||||
private float hueOffset = 0;
|
||||
private final String text;
|
||||
private final int density;
|
||||
private final int speed;
|
||||
private final float speed;
|
||||
|
||||
public RainbowComponent(String text, int density, int speed) {
|
||||
public RainbowComponent(String text, int density, float speed) {
|
||||
this.text = text;
|
||||
this.density = density;
|
||||
this.speed = speed;
|
||||
@ -19,15 +19,16 @@ public class RainbowComponent {
|
||||
|
||||
public Component getRainbowState() {
|
||||
Component builder = Component.empty();
|
||||
int hue = this.hueOffset;
|
||||
for(char c : text.toCharArray()) {
|
||||
TextColor color = TextColor.color(Color.getHSBColor((float) hue / 360, 1, 1).getRGB());
|
||||
float hue = this.hueOffset;
|
||||
for (char c : text.toCharArray()) {
|
||||
float normalizedHue = (hue % 360) / 360;
|
||||
TextColor color = TextColor.color(Color.getHSBColor(normalizedHue, 1, 1).getRGB());
|
||||
builder = builder.append(Component.text(c).color(color));
|
||||
hue += density;
|
||||
}
|
||||
|
||||
if(this.hueOffset > Byte.MAX_VALUE - speed) this.hueOffset = 0;
|
||||
this.hueOffset += (byte) speed;
|
||||
this.hueOffset = (this.hueOffset + speed) % 360;
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package eu.mhsl.craftattack.spawn.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) {
|
||||
player.playSound(getSound(sound.key()), Sound.Emitter.self());
|
||||
}
|
||||
|
||||
private Sound getSound(Key soundKey) {
|
||||
return Sound.sound(soundKey, Sound.Source.PLAYER, 1f, 1f);
|
||||
}
|
||||
|
||||
public void click() {
|
||||
playSound(org.bukkit.Sound.UI_BUTTON_CLICK);
|
||||
}
|
||||
|
||||
public void success() {
|
||||
playSound(org.bukkit.Sound.ENTITY_PLAYER_LEVELUP);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
playSound(org.bukkit.Sound.ENTITY_SILVERFISH_DEATH);
|
||||
}
|
||||
}
|
@ -1,3 +1,7 @@
|
||||
plugin:
|
||||
disabledAppliances:
|
||||
- NameOfApplianceClass
|
||||
|
||||
worldMuseum:
|
||||
uuid:
|
||||
connect-server-name: worldmuseum
|
||||
@ -42,11 +46,24 @@ help:
|
||||
spawn: "Der Weltspawn befindet sich bei x:0 y:0 z:0"
|
||||
|
||||
playerLimit:
|
||||
maxPlayers: 100
|
||||
maxPlayers: 10
|
||||
|
||||
whitelist:
|
||||
overrideIntegrityCheck: false
|
||||
api: https://mhsl.eu/craftattack/api/user
|
||||
|
||||
tablist:
|
||||
interface: eth0
|
||||
interface: eth0
|
||||
|
||||
outlawed:
|
||||
voluntarily: []
|
||||
|
||||
packselect:
|
||||
packs:
|
||||
- somepack:
|
||||
name: "Texture pack name"
|
||||
description: "Texture pack description"
|
||||
author: "Pack Author(s)"
|
||||
url: "https://example.com/download/pack.zip"
|
||||
hash: "" # SHA1 hash of ZIP file (will be auto determined by the server on startup when not set)
|
||||
icon: "" # base64 player-head texture, can be obtained from sites like https://minecraft-heads.com/ under developers > Value
|
@ -37,5 +37,8 @@ commands:
|
||||
panicBan:
|
||||
vogelfrei:
|
||||
settings:
|
||||
texturepack:
|
||||
maintanance:
|
||||
yearRank:
|
||||
msg:
|
||||
r:
|
Loading…
x
Reference in New Issue
Block a user