added texture pack selector
This commit is contained in:
parent
f49cca7f33
commit
f89a935c05
src/main
java/eu/mhsl/craftattack/spawn
Main.java
appliance
appliances
packSelect
ChangePackCommand.javaPackConfiguration.javaPackConfigurationInventory.javaPackSelect.javaResourcePackInfoFactory.java
listeners
settings
util
resources
@ -19,6 +19,7 @@ import eu.mhsl.craftattack.spawn.appliances.hotbarRefill.HotbarRefill;
|
|||||||
import eu.mhsl.craftattack.spawn.appliances.kick.Kick;
|
import eu.mhsl.craftattack.spawn.appliances.kick.Kick;
|
||||||
import eu.mhsl.craftattack.spawn.appliances.knockDoor.KnockDoor;
|
import eu.mhsl.craftattack.spawn.appliances.knockDoor.KnockDoor;
|
||||||
import eu.mhsl.craftattack.spawn.appliances.outlawed.Outlawed;
|
import eu.mhsl.craftattack.spawn.appliances.outlawed.Outlawed;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.packSelect.PackSelect;
|
||||||
import eu.mhsl.craftattack.spawn.appliances.panicBan.PanicBan;
|
import eu.mhsl.craftattack.spawn.appliances.panicBan.PanicBan;
|
||||||
import eu.mhsl.craftattack.spawn.appliances.playerlimit.PlayerLimit;
|
import eu.mhsl.craftattack.spawn.appliances.playerlimit.PlayerLimit;
|
||||||
import eu.mhsl.craftattack.spawn.appliances.portableCrafting.PortableCrafting;
|
import eu.mhsl.craftattack.spawn.appliances.portableCrafting.PortableCrafting;
|
||||||
@ -80,8 +81,8 @@ public final class Main extends JavaPlugin {
|
|||||||
new HotbarRefill(),
|
new HotbarRefill(),
|
||||||
new ChatMention(),
|
new ChatMention(),
|
||||||
new DoubleDoor(),
|
new DoubleDoor(),
|
||||||
new KnockDoor()
|
|
||||||
new KnockDoor(),
|
new KnockDoor(),
|
||||||
|
new PackSelect(),
|
||||||
new GlowingBerries()
|
new GlowingBerries()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ import java.util.Optional;
|
|||||||
/**
|
/**
|
||||||
* Utility class which enables command name definition over a constructor.
|
* 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;
|
public String commandName;
|
||||||
protected Component errorMessage = Component.text("Fehler: ").color(NamedTextColor.RED);
|
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
|
* @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;
|
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;
|
private final T appliance;
|
||||||
|
|
||||||
public ApplianceSupplier() {
|
public CachedApplianceSupplier() {
|
||||||
this.appliance = Main.instance().getAppliance(Main.getApplianceType(getClass()));
|
this.appliance = Main.instance().getAppliance(Main.getApplianceType(getClass()));
|
||||||
}
|
}
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
171
src/main/java/eu/mhsl/craftattack/spawn/appliances/packSelect/PackConfigurationInventory.java
Normal file
171
src/main/java/eu/mhsl/craftattack/spawn/appliances/packSelect/PackConfigurationInventory.java
Normal file
@ -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,136 @@
|
|||||||
|
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 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() {
|
||||||
|
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()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
62
src/main/java/eu/mhsl/craftattack/spawn/appliances/packSelect/ResourcePackInfoFactory.java
Normal file
62
src/main/java/eu/mhsl/craftattack/spawn/appliances/packSelect/ResourcePackInfoFactory.java
Normal file
@ -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();
|
||||||
|
}
|
||||||
|
}
|
22
src/main/java/eu/mhsl/craftattack/spawn/appliances/packSelect/listeners/ClickPackInventoryListener.java
Normal file
22
src/main/java/eu/mhsl/craftattack/spawn/appliances/packSelect/listeners/ClickPackInventoryListener.java
Normal file
@ -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()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
16
src/main/java/eu/mhsl/craftattack/spawn/appliances/packSelect/listeners/ClosePackInventoryListener.java
Normal file
16
src/main/java/eu/mhsl/craftattack/spawn/appliances/packSelect/listeners/ClosePackInventoryListener.java
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
18
src/main/java/eu/mhsl/craftattack/spawn/appliances/packSelect/listeners/SetPacksOnJoinListener.java
Normal file
18
src/main/java/eu/mhsl/craftattack/spawn/appliances/packSelect/listeners/SetPacksOnJoinListener.java
Normal file
@ -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()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,6 @@ package eu.mhsl.craftattack.spawn.appliances.settings;
|
|||||||
|
|
||||||
public enum SettingCategory {
|
public enum SettingCategory {
|
||||||
Gameplay,
|
Gameplay,
|
||||||
Chat,
|
Visuals,
|
||||||
Misc,
|
Misc,
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,8 @@ public class Settings extends Appliance {
|
|||||||
new TechnicalTablistSetting(),
|
new TechnicalTablistSetting(),
|
||||||
new SettingsShortcutSetting(),
|
new SettingsShortcutSetting(),
|
||||||
new DoubleDoorSetting(),
|
new DoubleDoorSetting(),
|
||||||
new KnockDoorSetting()
|
new KnockDoorSetting(),
|
||||||
|
new PackSelectSetting()
|
||||||
);
|
);
|
||||||
|
|
||||||
settings.forEach(setting -> setting.initializeFromPlayer(player));
|
settings.forEach(setting -> setting.initializeFromPlayer(player));
|
||||||
|
50
src/main/java/eu/mhsl/craftattack/spawn/appliances/settings/datatypes/ActionSetting.java
Normal file
50
src/main/java/eu/mhsl/craftattack/spawn/appliances/settings/datatypes/ActionSetting.java
Normal file
@ -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 eu.mhsl.craftattack.spawn.appliances.settings.Settings;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.inventory.ClickType;
|
import org.bukkit.event.inventory.ClickType;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
import org.bukkit.persistence.PersistentDataContainer;
|
import org.bukkit.persistence.PersistentDataContainer;
|
||||||
@ -47,7 +48,7 @@ public abstract class BoolSetting extends Setting<Boolean> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void change(ClickType clickType) {
|
protected void change(Player player, ClickType clickType) {
|
||||||
this.state = !this.state;
|
this.state = !this.state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import com.google.gson.Gson;
|
|||||||
import eu.mhsl.craftattack.spawn.appliances.settings.Settings;
|
import eu.mhsl.craftattack.spawn.appliances.settings.Settings;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.inventory.ClickType;
|
import org.bukkit.event.inventory.ClickType;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
import org.bukkit.persistence.PersistentDataContainer;
|
import org.bukkit.persistence.PersistentDataContainer;
|
||||||
@ -87,7 +88,7 @@ public abstract class MultiBoolSetting<T> extends Setting<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void change(ClickType clickType) {
|
protected void change(Player player, ClickType clickType) {
|
||||||
var recordComponents = this.state.getClass().getRecordComponents();
|
var recordComponents = this.state.getClass().getRecordComponents();
|
||||||
|
|
||||||
int currentIndex = IntStream.range(0, recordComponents.length)
|
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 net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.inventory.ClickType;
|
import org.bukkit.event.inventory.ClickType;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
import org.bukkit.persistence.PersistentDataContainer;
|
import org.bukkit.persistence.PersistentDataContainer;
|
||||||
@ -57,7 +58,7 @@ public abstract class SelectSetting extends Setting<SelectSetting.Options.Option
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void change(ClickType clickType) {
|
protected void change(Player player, ClickType clickType) {
|
||||||
int optionModifier = clickType.equals(ClickType.LEFT) ? 1 : -1;
|
int optionModifier = clickType.equals(ClickType.LEFT) ? 1 : -1;
|
||||||
List<Options.Option> options = this.options.options;
|
List<Options.Option> options = this.options.options;
|
||||||
this.state = IntStream.range(0, options.size())
|
this.state = IntStream.range(0, options.size())
|
||||||
|
@ -37,7 +37,7 @@ public abstract class Setting<TDataType> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void triggerChange(Player p, ClickType clickType) {
|
public void triggerChange(Player p, ClickType clickType) {
|
||||||
this.change(clickType);
|
this.change(p, clickType);
|
||||||
toStorage(p.getPersistentDataContainer(), this.state());
|
toStorage(p.getPersistentDataContainer(), this.state());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ public abstract class Setting<TDataType> {
|
|||||||
protected abstract String description();
|
protected abstract String description();
|
||||||
protected abstract Material icon();
|
protected abstract Material icon();
|
||||||
public abstract ItemMeta buildMeta(ItemMeta meta);
|
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 TDataType defaultValue();
|
||||||
protected abstract void fromStorage(PersistentDataContainer container);
|
protected abstract void fromStorage(PersistentDataContainer container);
|
||||||
protected abstract void toStorage(PersistentDataContainer container, TDataType value);
|
protected abstract void toStorage(PersistentDataContainer container, TDataType value);
|
||||||
|
@ -9,7 +9,7 @@ import org.bukkit.Material;
|
|||||||
public class ChatMentionSetting extends MultiBoolSetting<ChatMentionSetting.ChatMentionConfig> implements CategorizedSetting {
|
public class ChatMentionSetting extends MultiBoolSetting<ChatMentionSetting.ChatMentionConfig> implements CategorizedSetting {
|
||||||
@Override
|
@Override
|
||||||
public SettingCategory category() {
|
public SettingCategory category() {
|
||||||
return SettingCategory.Chat;
|
return SettingCategory.Visuals;
|
||||||
}
|
}
|
||||||
|
|
||||||
public record ChatMentionConfig(
|
public record ChatMentionConfig(
|
||||||
|
37
src/main/java/eu/mhsl/craftattack/spawn/appliances/settings/settings/PackSelectSetting.java
Normal file
37
src/main/java/eu/mhsl/craftattack/spawn/appliances/settings/settings/PackSelectSetting.java
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.settings.settings;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.Main;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.packSelect.PackSelect;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -33,6 +33,6 @@ public class ShowJoinAndLeaveMessagesSetting extends BoolSetting implements Cate
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SettingCategory category() {
|
public SettingCategory category() {
|
||||||
return SettingCategory.Chat;
|
return SettingCategory.Visuals;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,14 @@ import org.bukkit.GameRule;
|
|||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class IteratorUtil {
|
public class IteratorUtil {
|
||||||
public static void worlds(Consumer<World> world) {
|
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) {
|
public static void setGameRules(Map<GameRule<Boolean>, Boolean> rules, boolean inverse) {
|
||||||
rules.forEach((gameRule, value) -> IteratorUtil.worlds(world -> world.setGameRule(gameRule, value ^ 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;
|
package eu.mhsl.craftattack.spawn.util.server;
|
||||||
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.geysermc.cumulus.form.SimpleForm;
|
||||||
import org.geysermc.floodgate.api.FloodgateApi;
|
import org.geysermc.floodgate.api.FloodgateApi;
|
||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
|
|
||||||
@ -24,4 +25,22 @@ public class Floodgate {
|
|||||||
public static void runJavaOnly(Player p, Consumer<Player> callback) {
|
public static void runJavaOnly(Player p, Consumer<Player> callback) {
|
||||||
if(!isBedrock(p)) callback.accept(p);
|
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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,9 @@ public class ComponentUtil {
|
|||||||
return Component.text().append(a.appendNewline().append(b)).build();
|
return Component.text().append(a.appendNewline().append(b)).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Stream<String> lineBreak(String text) {
|
||||||
|
return lineBreak(text, 50);
|
||||||
|
}
|
||||||
public static Stream<String> lineBreak(String text, int charactersPerLine) {
|
public static Stream<String> lineBreak(String text, int charactersPerLine) {
|
||||||
List<String> lines = new ArrayList<>();
|
List<String> lines = new ArrayList<>();
|
||||||
String[] words = text.split(" ");
|
String[] words = text.split(" ");
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -52,3 +52,13 @@ tablist:
|
|||||||
|
|
||||||
outlawed:
|
outlawed:
|
||||||
voluntarily: []
|
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
|
@ -36,4 +36,5 @@ commands:
|
|||||||
kick:
|
kick:
|
||||||
panicBan:
|
panicBan:
|
||||||
vogelfrei:
|
vogelfrei:
|
||||||
settings:
|
settings:
|
||||||
|
texturepack:
|
Loading…
x
Reference in New Issue
Block a user