added chat mentions, added setting categories

This commit is contained in:
Elias Müller 2024-08-25 19:26:14 +02:00
parent 4c4975b0a4
commit ebab4cbd34
16 changed files with 306 additions and 32 deletions

View File

@ -2,9 +2,10 @@ 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.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;
@ -73,7 +74,8 @@ public final class Main extends JavaPlugin {
new PortableCrafting(),
new AutoShulker(),
new AntiSignEdit(),
new HotbarRefill()
new HotbarRefill(),
new ChatMention()
);
Main.logger.info("Loading appliances...");

View File

@ -0,0 +1,66 @@
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;
import org.bukkit.event.Listener;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
public class ChatMention extends Appliance {
private static List<String> playerNames;
public String formatPlayer(String name) {
return "@" + name;
}
public List<String> getPlayerNames() {
return playerNames;
}
public void refreshPlayers() {
Bukkit.getScheduler().runTaskAsynchronously(
Main.instance(),
() -> playerNames = Arrays.stream(Bukkit.getOfflinePlayers())
.map(OfflinePlayer::getName)
.filter(Objects::nonNull)
.toList()
);
}
public void notifyPlayers(List<String> playerNames) {
playerNames.stream()
.distinct()
.map(Bukkit::getPlayer)
.filter(Objects::nonNull)
.filter(player -> Settings.instance()
.getSetting(player, Settings.Key.ChatMentions, ChatMentionSetting.ChatMentionConfig.class)
.notifyOnMention()
)
.forEach(player -> player.playSound(
Sound.sound(
org.bukkit.Sound.ENTITY_EXPERIENCE_ORB_PICKUP,
Sound.Source.PLAYER,
1.0f,
1.0f
)
));
}
@Override
public void onEnable() {
refreshPlayers();
}
@Override
protected @NotNull List<Listener> eventHandlers() {
return List.of(new ChatMentionListener());
}
}

View File

@ -0,0 +1,46 @@
package eu.mhsl.craftattack.spawn.appliances.chatMention;
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
import eu.mhsl.craftattack.spawn.appliances.settings.Settings;
import eu.mhsl.craftattack.spawn.appliances.settings.settings.ChatMentionSetting;
import io.papermc.paper.event.player.AsyncChatDecorateEvent;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import org.bukkit.event.EventHandler;
import java.util.ArrayList;
import java.util.List;
public class ChatMentionListener extends ApplianceListener<ChatMention> {
@SuppressWarnings("UnstableApiUsage")
@EventHandler
public void coloringEvent(AsyncChatDecorateEvent event) {
String message = PlainTextComponentSerializer.plainText().serialize(event.result());
List<String> words = List.of(message.split(" "));
List<String> mentioned = new ArrayList<>();
ChatMentionSetting.ChatMentionConfig config = Settings.instance()
.getSetting(event.player(), Settings.Key.ChatMentions, ChatMentionSetting.ChatMentionConfig.class);
Component result = words.stream()
.map(word -> {
String wordWithoutAnnotation = word.replace("@", "");
boolean isPlayer = getAppliance().getPlayerNames().contains(wordWithoutAnnotation);
if(isPlayer && config.applyMentions()) {
mentioned.add(wordWithoutAnnotation);
return Component.text(
getAppliance().formatPlayer(wordWithoutAnnotation),
NamedTextColor.GOLD
);
} else {
return Component.text(word);
}
})
.reduce((a, b) -> a.append(Component.text(" ")).append(b))
.orElseThrow();
getAppliance().notifyPlayers(mentioned);
event.result(result);
}
}

View File

@ -1,12 +1,25 @@
package eu.mhsl.craftattack.spawn.appliances.chatMessages;
import eu.mhsl.craftattack.spawn.appliance.Appliance;
import net.kyori.adventure.text.Component;
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.bukkit.event.Listener;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class ChatMessages extends Appliance {
public Component getReportablePlayerName(Player player) {
return Component
.text("")
.append(player.displayName())
.hoverEvent(HoverEvent.showText(Component.text("Klicke, um diesen Spieler zu reporten").color(NamedTextColor.GOLD)))
.clickEvent(ClickEvent.clickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/report " + player.getName() + " "));
}
@Override
@NotNull
protected List<Listener> eventHandlers() {

View File

@ -5,12 +5,9 @@ import eu.mhsl.craftattack.spawn.appliances.settings.Settings;
import eu.mhsl.craftattack.spawn.util.IteratorUtil;
import io.papermc.paper.event.player.AsyncChatEvent;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import org.bukkit.Color;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.player.PlayerJoinEvent;
@ -24,7 +21,7 @@ public class ChatMessagesListener extends ApplianceListener<ChatMessages> {
event.renderer(
(source, sourceDisplayName, message, viewer) ->
Component.text("")
.append(getReportablePlayerName(source))
.append(getAppliance().getReportablePlayerName(source))
.append(Component.text(" > ").color(TextColor.color(Color.GRAY.asRGB())))
.append(message).color(TextColor.color(Color.SILVER.asRGB()))
);
@ -38,7 +35,7 @@ public class ChatMessagesListener extends ApplianceListener<ChatMessages> {
player.sendMessage(
Component
.text(">>> ").color(NamedTextColor.GREEN)
.append(getReportablePlayerName(event.getPlayer()))
.append(getAppliance().getReportablePlayerName(event.getPlayer()))
);
});
}
@ -51,7 +48,7 @@ public class ChatMessagesListener extends ApplianceListener<ChatMessages> {
player.sendMessage(
Component
.text("<<< ").color(NamedTextColor.RED)
.append(getReportablePlayerName(event.getPlayer()))
.append(getAppliance().getReportablePlayerName(event.getPlayer()))
);
});
}
@ -69,12 +66,4 @@ public class ChatMessagesListener extends ApplianceListener<ChatMessages> {
.color(TextColor.color(Color.SILVER.asRGB()))
);
}
private Component getReportablePlayerName(Player player) {
return Component
.text("")
.append(player.displayName())
.hoverEvent(HoverEvent.showText(Component.text("Klicke, um diesen Spieler zu reporten").color(NamedTextColor.GOLD)))
.clickEvent(ClickEvent.clickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/report " + player.getName() + " "));
}
}

View File

@ -0,0 +1,5 @@
package eu.mhsl.craftattack.spawn.appliances.settings;
public interface CategorizedSetting {
SettingCategory category();
}

View File

@ -0,0 +1,7 @@
package eu.mhsl.craftattack.spawn.appliances.settings;
public enum SettingCategory {
Gameplay,
Chat,
Misc,
}

View File

@ -14,8 +14,10 @@ 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.util.concurrent.atomic.AtomicInteger;
public class Settings extends Appliance {
private static Settings settingsInstance;
@ -28,6 +30,7 @@ public class Settings extends Appliance {
AutoShulker,
SignEdit,
HotbarReplacer,
ChatMentions,
}
public static Settings instance() {
@ -47,13 +50,14 @@ public class Settings extends Appliance {
if(settingsCache.containsKey(player)) return settingsCache.get(player);
List<Setting<?>> settings = List.of(
new TechnicalTablistSetting(),
new ShowJoinAndLeaveMessagesSetting(),
new EnablePortableCraftingSetting(),
new EnableSettingsShortcutSetting(),
new PortableCraftingSetting(),
new AutoShulkerSetting(),
new SignEditSetting(),
new HotbarReplaceSetting()
new HotbarReplaceSetting(),
new ChatMentionSetting(),
new ShowJoinAndLeaveMessagesSetting(),
new TechnicalTablistSetting(),
new SettingsShortcutSetting()
);
settings.forEach(setting -> setting.initializeFromPlayer(player));
@ -75,13 +79,58 @@ public class Settings extends Appliance {
}
public void openSettings(Player player) {
Inventory inventory = Bukkit.createInventory(null, 9, Component.text("Einstellungen"));
List<Setting<?>> settings = getSettings(player);
settings.forEach(setting -> inventory.addItem(setting.buildItem()));
Inventory inventory = Bukkit.createInventory(null, calculateInvSize(settings), Component.text("Einstellungen"));
AtomicInteger row = new AtomicInteger(0);
Arrays.stream(SettingCategory.values())
.forEach(category -> {
List<Setting<?>> categorizedSettings = settings.stream()
.filter(setting -> setting instanceof CategorizedSetting)
.filter(setting -> ((CategorizedSetting) setting).category().equals(category))
.toList();
for (int i = 0; i < categorizedSettings.size(); i++) {
int slot = row.get() * 9 + i % 9;
inventory.setItem(slot, categorizedSettings.get(i).buildItem());
if (i % 9 == 8) {
row.incrementAndGet();
}
}
row.incrementAndGet();
});
List<Setting<?>> uncategorizedSettings = settings.stream()
.filter(setting -> !(setting instanceof CategorizedSetting))
.toList();
for (int i = 0; i < uncategorizedSettings.size(); i++) {
int slot = row.get() * 9 + i % 9;
inventory.setItem(slot, uncategorizedSettings.get(i).buildItem());
if (i % 9 == 8) {
row.incrementAndGet();
}
}
player.openInventory(inventory);
this.openSettingsInventories.put(player, new OpenSettingsInventory(inventory, settings));
}
private int calculateInvSize(List<Setting<?>> settings) {
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))
.count())
.map(itemCount -> itemCount + countOfUncategorized)
.map(itemCount -> (int) Math.ceil((double) itemCount / 9))
.reduce(Integer::sum)
.orElse(1) * 9;
}
public void onSettingsClose(Player player) {
if(!openSettingsInventories.containsKey(player)) return;
openSettingsInventories.remove(player);

View File

@ -1,5 +1,7 @@
package eu.mhsl.craftattack.spawn.appliances.settings.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.SelectSetting;
import org.bukkit.Material;
@ -8,7 +10,7 @@ import org.bukkit.NamespacedKey;
import java.util.List;
import java.util.Locale;
public class AutoShulkerSetting extends SelectSetting {
public class AutoShulkerSetting extends SelectSetting implements CategorizedSetting {
private static final String namespace = AutoShulkerSetting.class.getSimpleName().toLowerCase(Locale.ROOT);
public static Options.Option disabled = new Options.Option("Deaktiviert", new NamespacedKey(namespace, "disabled"));
public static Options.Option notFromPlayers = new Options.Option("Keine manuell gedroppten Items", new NamespacedKey(namespace, "noplayerdrops"));
@ -40,4 +42,9 @@ public class AutoShulkerSetting extends SelectSetting {
protected Options.Option defaultValue() {
return disabled;
}
@Override
public SettingCategory category() {
return SettingCategory.Gameplay;
}
}

View File

@ -0,0 +1,48 @@
package eu.mhsl.craftattack.spawn.appliances.settings.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.MultiBoolSetting;
import org.bukkit.Material;
public class ChatMentionSetting extends MultiBoolSetting<ChatMentionSetting.ChatMentionConfig> implements CategorizedSetting {
@Override
public SettingCategory category() {
return SettingCategory.Chat;
}
public record ChatMentionConfig(
@DisplayName("Spielernamen hervorheben") boolean applyMentions,
@DisplayName("Benachrichtigungston") boolean notifyOnMention
) {}
public ChatMentionSetting() {
super(Settings.Key.ChatMentions);
}
@Override
protected String title() {
return "Erwähnungen im Chat";
}
@Override
protected String description() {
return "Erwähnungen werden automatisch im Chat angewandt und der Empfänger erhält einen Signalton";
}
@Override
protected Material icon() {
return Material.FEATHER;
}
@Override
protected ChatMentionConfig defaultValue() {
return new ChatMentionConfig(true, true);
}
@Override
public Class<?> dataType() {
return ChatMentionConfig.class;
}
}

View File

@ -1,10 +1,17 @@
package eu.mhsl.craftattack.spawn.appliances.settings.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.MultiBoolSetting;
import org.bukkit.Material;
public class HotbarReplaceSetting extends MultiBoolSetting<HotbarReplaceSetting.HotbarReplaceConfig> {
public class HotbarReplaceSetting extends MultiBoolSetting<HotbarReplaceSetting.HotbarReplaceConfig> implements CategorizedSetting {
@Override
public SettingCategory category() {
return SettingCategory.Gameplay;
}
public record HotbarReplaceConfig(
@DisplayName("Blöcke") boolean onBlocks,
@DisplayName("Werkzeuge") boolean onTools,

View File

@ -1,11 +1,13 @@
package eu.mhsl.craftattack.spawn.appliances.settings.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;
public class EnablePortableCraftingSetting extends BoolSetting {
public EnablePortableCraftingSetting() {
public class PortableCraftingSetting extends BoolSetting implements CategorizedSetting {
public PortableCraftingSetting() {
super(Settings.Key.EnablePortableCrafting);
}
@ -28,4 +30,9 @@ public class EnablePortableCraftingSetting extends BoolSetting {
protected Boolean defaultValue() {
return true;
}
@Override
public SettingCategory category() {
return SettingCategory.Gameplay;
}
}

View File

@ -1,11 +1,13 @@
package eu.mhsl.craftattack.spawn.appliances.settings.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;
public class EnableSettingsShortcutSetting extends BoolSetting {
public EnableSettingsShortcutSetting() {
public class SettingsShortcutSetting extends BoolSetting implements CategorizedSetting {
public SettingsShortcutSetting() {
super(Settings.Key.EnableSettingsShortcut);
}
@ -28,4 +30,9 @@ public class EnableSettingsShortcutSetting extends BoolSetting {
protected Boolean defaultValue() {
return false;
}
@Override
public SettingCategory category() {
return SettingCategory.Misc;
}
}

View File

@ -1,10 +1,12 @@
package eu.mhsl.craftattack.spawn.appliances.settings.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;
public class ShowJoinAndLeaveMessagesSetting extends BoolSetting {
public class ShowJoinAndLeaveMessagesSetting extends BoolSetting implements CategorizedSetting {
public ShowJoinAndLeaveMessagesSetting() {
super(Settings.Key.ShowJoinAndLeaveMessages);
}
@ -28,4 +30,9 @@ public class ShowJoinAndLeaveMessagesSetting extends BoolSetting {
protected Boolean defaultValue() {
return true;
}
@Override
public SettingCategory category() {
return SettingCategory.Chat;
}
}

View File

@ -1,5 +1,7 @@
package eu.mhsl.craftattack.spawn.appliances.settings.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.SelectSetting;
import org.bukkit.Material;
@ -8,7 +10,7 @@ import org.bukkit.NamespacedKey;
import java.util.List;
import java.util.Locale;
public class SignEditSetting extends SelectSetting {
public class SignEditSetting extends SelectSetting implements CategorizedSetting {
private static final String namespace = SignEditSetting.class.getSimpleName().toLowerCase(Locale.ROOT);
public static Options.Option editable = new Options.Option("Bearbeitbar", new NamespacedKey(namespace, "editable"));
public static Options.Option editableWhenEmpty = new Options.Option("Bearbeitbar wenn leer", new NamespacedKey(namespace, "emptyeditable"));
@ -40,4 +42,9 @@ public class SignEditSetting extends SelectSetting {
protected Options.Option defaultValue() {
return editableWhenEmpty;
}
@Override
public SettingCategory category() {
return SettingCategory.Gameplay;
}
}

View File

@ -1,10 +1,12 @@
package eu.mhsl.craftattack.spawn.appliances.settings.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;
public class TechnicalTablistSetting extends BoolSetting {
public class TechnicalTablistSetting extends BoolSetting implements CategorizedSetting {
public TechnicalTablistSetting() {
super(Settings.Key.TechnicalTab);
}
@ -28,4 +30,9 @@ public class TechnicalTablistSetting extends BoolSetting {
protected Boolean defaultValue() {
return false;
}
@Override
public SettingCategory category() {
return SettingCategory.Misc;
}
}