Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,24 +1,36 @@
package space.yurisi.universecorev2.subplugins.autocollect;

import org.bukkit.Bukkit;
import space.yurisi.universecorev2.UniverseCoreV2;
import space.yurisi.universecorev2.subplugins.SubPlugin;
import space.yurisi.universecorev2.subplugins.autocollect.command.AutoCollectCommand;
import space.yurisi.universecorev2.subplugins.autocollect.data.AutoCollectMap;
import space.yurisi.universecorev2.subplugins.autocollect.event.AutoCollectListener;

public class AutoCollect implements SubPlugin {

private static AutoCollect instance;
private AutoCollectManager manager;

public static AutoCollect getInstance() {
return instance;
}

public AutoCollectManager getManager() {
return manager;
}

@Override
public void onEnable(UniverseCoreV2 core) {
new AutoCollectMap();
Bukkit.getPluginManager().registerEvents(new AutoCollectListener(), core);
core.getCommand("autocollect").setExecutor(new AutoCollectCommand());
instance = this;
this.manager = new AutoCollectManager();
AutoCollectMessageFormatter messageFormatter = new AutoCollectMessageFormatter();

core.getCommand("autocollect").setExecutor(new AutoCollectCommand(manager, messageFormatter));
core.getServer().getPluginManager().registerEvents(new AutoCollectEvent(manager, messageFormatter), core);
}

@Override
public void onDisable() {
//NOOP
manager.clear();
manager = null;
instance = null;
}

@Override
Expand All @@ -28,6 +40,6 @@ public String getName() {

@Override
public String getVersion() {
return "1.0.0";
return "2.0.0";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package space.yurisi.universecorev2.subplugins.autocollect;

import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;

public class AutoCollectCommand implements CommandExecutor {

private final AutoCollectManager manager;
private final AutoCollectMessageFormatter messageFormatter;

public AutoCollectCommand(AutoCollectManager manager, AutoCollectMessageFormatter messageFormatter) {
this.manager = manager;
this.messageFormatter = messageFormatter;
}

@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage(messageFormatter.formatError("このコマンドはプレイヤーのみ使用できます"));
return false;
}

AutoCollectState newState = manager.toggleAutoCollect(player);
sender.sendMessage(messageFormatter.formatToggleMessage(player, newState));

return true;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package space.yurisi.universecorev2.subplugins.autocollect;

import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockDropItemEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.EntityDropItemEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class AutoCollectEvent implements Listener {

private final AutoCollectManager manager;
private final AutoCollectMessageFormatter messageFormatter;

public AutoCollectEvent(@NotNull AutoCollectManager manager, @NotNull AutoCollectMessageFormatter messageFormatter) {
this.manager = manager;
this.messageFormatter = messageFormatter;
}

@EventHandler(priority = EventPriority.HIGHEST)
public void onBlockDrop(BlockDropItemEvent event) {
if (event.isCancelled()) return;
if (event.getItems().isEmpty()) return;

Player player = event.getPlayer();

extractPlayer(player)
.filter(manager::isAutoCollectEnabled)
.ifPresent(target -> {
collectItems(target, event.getItems());
event.getItems().clear();
});
}

@EventHandler(priority = EventPriority.HIGH)
public void onEntityDrop(@NotNull EntityDropItemEvent event) {
if (event.isCancelled()) return;
if (!(event.getEntity() instanceof Player player)) return;

extractPlayer(player)
.filter(manager::isAutoCollectEnabled)
.ifPresent(target -> {
event.setCancelled(true);
collectItems(target, List.of(event.getItemDrop()));
});
}

@EventHandler(priority = EventPriority.HIGHEST)
public void onEntityDeath(@NotNull EntityDeathEvent event) {
Player killer = event.getEntity().getKiller();
extractPlayer(killer)
.filter(manager::isAutoCollectEnabled)
.ifPresent(target -> {
collectItemStacks(target, event.getDrops());
event.getDrops().clear();
});
}

@EventHandler
public void onJoin(PlayerJoinEvent event) {
extractPlayer(event.getPlayer())
.filter(player -> !manager.isRegistered(player))
.ifPresent(manager::registerPlayer);
}

/**
* プレイヤーのインベントリにアイテムを収集する
*
* @param player 収集対象のプレイヤー
* @param itemCollection 収集するアイテムのコレクション
*/
private void collectItems(@NotNull Player player, @NotNull Collection<Item> itemCollection) {
if (itemCollection.isEmpty()) return;

ItemStack[] items = itemCollection.stream()
.map(Item::getItemStack)
.toArray(ItemStack[]::new);

PlayerInventory inventory = player.getInventory();
Map<Integer, ItemStack> failedToAdd = inventory.addItem(items);

handleFailedItems(player, failedToAdd);
}

/**
* プレイヤーのインベントリにアイテムスタックを収集する
*
* @param player 収集対象のプレイヤー
* @param itemStacks 収集するアイテムスタックのコレクション
*/
private void collectItemStacks(@NotNull Player player, @NotNull Collection<ItemStack> itemStacks) {
if (itemStacks.isEmpty()) return;

ItemStack[] items = itemStacks.toArray(new ItemStack[0]);

PlayerInventory inventory = player.getInventory();
Map<Integer, ItemStack> failedToAdd = inventory.addItem(items);

handleFailedItems(player, failedToAdd);
}

/**
* インベントリに収集できなかったアイテムをプレイヤーの位置にドロップし、通知を送る
*
* @param player 対象のプレイヤー
* @param failedItems 収集に失敗したアイテムのマップ
*/
private void handleFailedItems(@NotNull Player player, @NotNull Map<Integer, ItemStack> failedItems) {
if (failedItems.isEmpty()) return;

failedItems.values().forEach( itemStack ->
player.getWorld().dropItem(player.getLocation(), itemStack)
);

player.sendActionBar(messageFormatter.formatError("インベントリが満杯のため,アイテムをドロップしました"));
}

/**
* Player を Optional でラップして返す
* Spigot API の Player は null になる可能性があるため Optional で扱うことで null チェックを強制する
*
* @param player Spigot API の Player オブジェクト
* @return Player の Optional ラップ (null の場合は Optional.empty() を返す)
*/
@NotNull
private Optional<Player> extractPlayer(Player player) {
return Optional.ofNullable(player);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package space.yurisi.universecorev2.subplugins.autocollect;

import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;

/**
* プレイヤーの自動回収機能を管理するクラス.
* プレイヤーのUUIDを使用して,プレイヤーごとの自動回収機能の状態を管理します.
*/
public class AutoCollectManager {

/**
* 各プレイヤーの自動回収状態を保持するマップ.
* キー: プレイヤーのUUID, 値: 自動回収が有効かどうか
*/
private final Map<UUID, AutoCollectState> stateMap;

public AutoCollectManager() {
this.stateMap = new HashMap<>();
}

/**
* 指定されたプレイヤーの自動回収状態を切り替えます.
* 切り替え後の状態を返します.
*
* @param player プレイヤー
* @return 切り替え後の自動回収状態
*/
@NotNull
public AutoCollectState toggleAutoCollect(@NotNull Player player) {
UUID playerId = player.getUniqueId();
AutoCollectState currentState = getStateOrDefault(playerId);
AutoCollectState newState = currentState.toggle();
stateMap.put(playerId, newState);
return newState;
}

/**
* 指定されたプレイヤーの自動回収が有効かどうかを取得します.
* 未登録の場合はデフォルトでfalseを返します.
*
* @param player プレイヤー
* @return 自動回収が有効かどうか
*/
public boolean isAutoCollectEnabled(@NotNull Player player) {
return getStateOrDefault(player.getUniqueId()).isEnabled();
}

/**
* 指定されたプレイヤーの自動回収状態を取得します.
* 未登録の場合は空のOptionalを返します.
*
* @param player プレイヤー
* @return プレイヤーの自動回収状態
*/
@NotNull
public Optional<AutoCollectState> getState(@NotNull Player player) {
return Optional.ofNullable(stateMap.get(player.getUniqueId()));
}

/**
* 指定されたプレイヤーの自動回収状態を設定します.
* 既に登録されている場合は上書きされます.
*
* @param player プレイヤー
* @param state プレイヤーの自動回収状態
*/
public void setState(@NotNull Player player, @NotNull AutoCollectState state) {
stateMap.put(player.getUniqueId(), state);
}

/**
* 指定されたプレイヤーが登録されているかどうかを確認します.
* 登録されていない場合はfalseを返します.
*
* @param player プレイヤー
* @return 登録されているかどうか
*/
public boolean isRegistered(@NotNull Player player) {
return stateMap.containsKey(player.getUniqueId());
}

/**
* 指定されたプレイヤーを登録します.
* 既に登録されている場合はfalseを返します.
*
* @param player プレイヤー
* @return 登録に成功したかどうか
*/
public boolean registerPlayer(@NotNull Player player) {
UUID uuid = player.getUniqueId();
if (stateMap.containsKey(uuid)) {
return false;
}
stateMap.put(uuid, AutoCollectState.DISABLED);
return true;
}

/**
* 指定されたプレイヤーの登録を解除します.
* 登録されていなかった場合は空のOptionalを返します.
*
* @param player プレイヤー
* @return 解除されたプレイヤーの自動回収状態
*/
@NotNull
public Optional<AutoCollectState> unregisterPlayer(@NotNull Player player) {
return Optional.ofNullable(stateMap.remove(player.getUniqueId()));
}

/**
* 全てのプレイヤーの自動回収状態をクリアします.
*/
public void clear() {
stateMap.clear();
}

/**
* 登録されているプレイヤーの数を取得します.
*
* @return 登録されているプレイヤーの数
*/
public int getRegisteredPlayerCount() {
return stateMap.size();
}

/**
* 自動回収が有効なプレイヤーの数を取得します.
*
* @return 自動回収が有効なプレイヤーの数
*/
public long getEnabledPlayerCount() {
return stateMap.values().stream()
.filter(AutoCollectState::isEnabled)
.count();
}



/**
* 指定されたプレイヤーの自動回収状態を取得します.
* 未登録の場合はデフォルトでDISABLEDを返します.
*
* @param playerId プレイヤーのUUID
* @return プレイヤーの自動回収状態
*/
@NotNull
private AutoCollectState getStateOrDefault(@NotNull UUID playerId) {
return stateMap.getOrDefault(playerId, AutoCollectState.DISABLED);
}

}
Loading