diff --git a/build.gradle b/build.gradle index 49cb1f6..2e6f0b6 100644 --- a/build.gradle +++ b/build.gradle @@ -58,3 +58,10 @@ tasks.register('copyJarToServer', Exec) { commandLine 'scp', 'build/libs/spawn-1.0-all.jar', 'root@10.20.6.1:/home/minecraft/server/plugins' } + +tasks.register('copyJarToTestServer', Exec) { + dependsOn shadowJar + mustRunAfter shadowJar + + commandLine 'cp', 'build/libs/spawn-1.0-all.jar', '/home/elias/Dokumente/mcTestServer/plugins/spawn-1.0-all.jar' +} diff --git a/src/main/java/eu/mhsl/craftattack/spawn/appliances/hotbarRefill/ItemRefillListener.java b/src/main/java/eu/mhsl/craftattack/spawn/appliances/hotbarRefill/ItemRefillListener.java index 2f733a0..d001598 100644 --- a/src/main/java/eu/mhsl/craftattack/spawn/appliances/hotbarRefill/ItemRefillListener.java +++ b/src/main/java/eu/mhsl/craftattack/spawn/appliances/hotbarRefill/ItemRefillListener.java @@ -2,6 +2,8 @@ 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; import org.bukkit.event.player.PlayerItemBreakEvent; @@ -9,26 +11,34 @@ import org.bukkit.event.player.PlayerItemConsumeEvent; import org.bukkit.inventory.ItemStack; public class ItemRefillListener extends ApplianceListener { + private HotbarReplaceSetting.HotbarReplaceConfig getPlayerSetting(Player player) { + return Settings.instance().getSetting( + player, + Settings.Key.HotbarReplacer, + HotbarReplaceSetting.HotbarReplaceConfig.class + ); + } + @EventHandler public void blockPlace(BlockPlaceEvent event) { - if(!Settings.instance().getSetting(event.getPlayer(), Settings.Key.HotbarReplacer, Boolean.class)) return; - ItemStack stackInHand = event.getItemInHand(); + if(stackInHand.getAmount() != 1) return; if(stackInHand.getType().getMaxDurability() > 0) return; + + if(!getPlayerSetting(event.getPlayer()).onBlocks()) return; getAppliance().handleHotbarChange(event.getPlayer(), stackInHand); } @EventHandler public void onPlayerItemBreak(PlayerItemBreakEvent event) { - if(!Settings.instance().getSetting(event.getPlayer(), Settings.Key.HotbarReplacer, Boolean.class)) return; + if(!getPlayerSetting(event.getPlayer()).onTools()) return; getAppliance().handleHotbarChange(event.getPlayer(), event.getBrokenItem()); } - @EventHandler public void onPlayerItemConsume(PlayerItemConsumeEvent event) { - if(!Settings.instance().getSetting(event.getPlayer(), Settings.Key.HotbarReplacer, Boolean.class)) return; + if(!getPlayerSetting(event.getPlayer()).onConsumable()) return; getAppliance().handleHotbarChange(event.getPlayer(), event.getItem()); } diff --git a/src/main/java/eu/mhsl/craftattack/spawn/appliances/settings/datatypes/MultiBoolSetting.java b/src/main/java/eu/mhsl/craftattack/spawn/appliances/settings/datatypes/MultiBoolSetting.java new file mode 100644 index 0000000..fb61063 --- /dev/null +++ b/src/main/java/eu/mhsl/craftattack/spawn/appliances/settings/datatypes/MultiBoolSetting.java @@ -0,0 +1,150 @@ +package eu.mhsl.craftattack.spawn.appliances.settings.datatypes; + +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.event.inventory.ClickType; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.RecordComponent; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.stream.IntStream; + +public abstract class MultiBoolSetting extends Setting { + private String cursorPosition; + + public MultiBoolSetting(Settings.Key key) { + super(key); + } + + @Retention(RetentionPolicy.RUNTIME) + public @interface DisplayName { + String value(); + } + + @Override + public ItemMeta buildMeta(ItemMeta meta) { + record SettingField(String name, String displayName, Boolean value) {} + + meta.displayName(Component.text(title(), NamedTextColor.WHITE)); + List lore = new ArrayList<>(); + lore.add(Component.text("Status: ", NamedTextColor.DARK_GRAY)); + + lore.addAll( + Arrays.stream(this.state.getClass().getRecordComponents()) + .map(component -> { + try { + Method method = this.state.getClass().getDeclaredMethod(component.getName()); + Boolean value = (Boolean) method.invoke(this.state); + + DisplayName annotation = component.getAnnotation(DisplayName.class); + String displayName = annotation != null + ? annotation.value() + : component.getName(); + + return new SettingField(component.getName(), displayName, value); + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + throw new RuntimeException(e); + } + }) + .map(field -> { + if (cursorPosition == null) cursorPosition = field.name; + boolean isSelected = field.name.equals(this.cursorPosition); + return Component.text() + .append(Component.text( + isSelected ? "> " : " ", + isSelected ? NamedTextColor.GREEN : NamedTextColor.GRAY) + ) + .append(Component.text( + field.displayName + ": ", + isSelected ? NamedTextColor.DARK_GREEN : NamedTextColor.GRAY) + ) + .append(Component.text( + field.value ? "Aktiviert" : "Deaktiviert", + field.value ? NamedTextColor.GREEN : NamedTextColor.RED) + ) + .build(); + }) + .toList() + ); + lore.add(Component.empty()); + lore.addAll(buildDescription(description())); + lore.add(Component.empty()); + lore.add(Component.text("Linksklick", NamedTextColor.AQUA).append(Component.text(" zum Wählen der Option", NamedTextColor.GRAY))); + lore.add(Component.text("Rechtsklick", NamedTextColor.AQUA).append(Component.text(" zum Ändern des Wertes", NamedTextColor.GRAY))); + meta.lore(lore); + return meta; + } + + @Override + protected void change(ClickType clickType) { + var recordComponents = this.state.getClass().getRecordComponents(); + + int currentIndex = IntStream.range(0, recordComponents.length) + .filter(i -> recordComponents[i].getName().equals(this.cursorPosition)) + .findFirst() + .orElse(-1); + + if (clickType.equals(ClickType.LEFT)) { + currentIndex = (currentIndex + 1) % recordComponents.length; + this.cursorPosition = recordComponents[currentIndex].getName(); + } else if (clickType.equals(ClickType.RIGHT)) { + try { + Object[] values = Arrays.stream(recordComponents) + .map(rc -> { + try { + return this.state.getClass().getDeclaredMethod(rc.getName()).invoke(this.state); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + }) + .toArray(); + + Method getter = this.state.getClass().getDeclaredMethod(this.cursorPosition); + boolean currentValue = (Boolean) getter.invoke(this.state); + values[currentIndex] = !currentValue; + + //noinspection unchecked + this.state = (T) this.state.getClass().getConstructor( + Arrays.stream(recordComponents).map(RecordComponent::getType).toArray(Class[]::new) + ).newInstance(values); + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException | InstantiationException e) { + throw new RuntimeException(e); + } + } + } + + @Override + protected void fromStorage(PersistentDataContainer container) { + String data = container.has(getNamespacedKey()) + ? Objects.requireNonNull(container.get(getNamespacedKey(), PersistentDataType.STRING)) + : new Gson().toJson(defaultValue()); + + try { + //noinspection unchecked + this.state = (T) new Gson().fromJson(data, dataType()); + } catch(Exception e) { + this.state = defaultValue(); + } + } + + @Override + protected void toStorage(PersistentDataContainer container, T value) { + container.set(getNamespacedKey(), PersistentDataType.STRING, new Gson().toJson(value)); + } + + @Override + public T state() { + return this.state; + } +} diff --git a/src/main/java/eu/mhsl/craftattack/spawn/appliances/settings/datatypes/SelectSetting.java b/src/main/java/eu/mhsl/craftattack/spawn/appliances/settings/datatypes/SelectSetting.java index 45ed4db..7f56cf6 100644 --- a/src/main/java/eu/mhsl/craftattack/spawn/appliances/settings/datatypes/SelectSetting.java +++ b/src/main/java/eu/mhsl/craftattack/spawn/appliances/settings/datatypes/SelectSetting.java @@ -43,7 +43,10 @@ public abstract class SelectSetting extends Setting { boolean isSelected = option.equals(this.state); - return Component.text("> " + option.name, isSelected ? NamedTextColor.GREEN : NamedTextColor.GRAY); + return Component.text() + .append(Component.text(isSelected ? "> " : " ", isSelected ? NamedTextColor.GREEN : NamedTextColor.GRAY)) + .append(Component.text(option.name, isSelected ? NamedTextColor.DARK_GREEN : NamedTextColor.DARK_GRAY)) + .build(); }) .toList() ); @@ -62,9 +65,9 @@ public abstract class SelectSetting extends Setting { int nextIndex = i + optionModifier; if (nextIndex >= options.size()) { - return options.get(0); + return options.getFirst(); } else if (nextIndex < 0) { - return options.get(options.size() - 1); + return options.getLast(); } else { return options.get(nextIndex); } diff --git a/src/main/java/eu/mhsl/craftattack/spawn/appliances/settings/settings/HotbarReplaceSetting.java b/src/main/java/eu/mhsl/craftattack/spawn/appliances/settings/settings/HotbarReplaceSetting.java index b2b454a..1331882 100644 --- a/src/main/java/eu/mhsl/craftattack/spawn/appliances/settings/settings/HotbarReplaceSetting.java +++ b/src/main/java/eu/mhsl/craftattack/spawn/appliances/settings/settings/HotbarReplaceSetting.java @@ -1,10 +1,16 @@ package eu.mhsl.craftattack.spawn.appliances.settings.settings; import eu.mhsl.craftattack.spawn.appliances.settings.Settings; -import eu.mhsl.craftattack.spawn.appliances.settings.datatypes.BoolSetting; +import eu.mhsl.craftattack.spawn.appliances.settings.datatypes.MultiBoolSetting; import org.bukkit.Material; -public class HotbarReplaceSetting extends BoolSetting { +public class HotbarReplaceSetting extends MultiBoolSetting { + public record HotbarReplaceConfig( + @DisplayName("Blöcke") boolean onBlocks, + @DisplayName("Werkzeuge") boolean onTools, + @DisplayName("Essen") boolean onConsumable + ) {} + public HotbarReplaceSetting() { super(Settings.Key.HotbarReplacer); } @@ -16,7 +22,7 @@ public class HotbarReplaceSetting extends BoolSetting { @Override protected String description() { - return "Verschiebe automatisch Blöcke von deinem Inventar in die Hotbar, wenn diese verbraucht werden"; + return "Verschiebe Items automatisch von deinem Inventar in die Hotbar, wenn diese verbraucht werden"; } @Override @@ -25,7 +31,12 @@ public class HotbarReplaceSetting extends BoolSetting { } @Override - protected Boolean defaultValue() { - return false; + protected HotbarReplaceConfig defaultValue() { + return new HotbarReplaceConfig(false, false, false); + } + + @Override + public Class dataType() { + return HotbarReplaceConfig.class; } }