从零开始的探索
技术基础薄弱,但热情满满
第一版实现了最基础的功能监盒子的破坏时间
同时实现盒子的复制逻辑
代码结构也比较简单 有些逻辑写死为后续更改全部推翻原有逻辑
应为经验不足 导致后面出现了许多bug
例如: 游戏内有多种染色盒子但是插件仅仅支持一种 同时因为没有考虑盒子内物品的数据
导致复制后盒子内的所有物品信息全部丢失 代码全部卸载了一个java类里面 后面优化各种函数错误
同时盒子数量的复制条件写死在了源码里面 导致每次想快速测试都需要从新更改源码
例如下述代码 就是逻辑写死 导致物品内部数据丢失 为后续埋雷
private void dropShulkerBoxes(BlockBreakEvent event) {
UUID playerUUID = event.getPlayer().getUniqueId();
int count = (Integer)this.shulkerBoxCount.getOrDefault(playerUUID, 0);
++count;
if (count == 10) {
event.setDropItems(false);
event.getBlock().getWorld().dropItemNaturally(event.getBlock().getLocation(), new ItemStack(Material.SHULKER_BOX, 2));
count = 0;
}
this.shulkerBoxCount.put(playerUUID, count);
}
小组成员分工
- 边世恒 : 负责主逻辑和时间监听以及处理后续bug
- 薛锡冰 : 负责测试插件反馈bug
- 宋欣雨 : 负责文档与README的修改工作
- 左广圆 : 负责项目结构整理
最终版项目:重构、优化与专业化
随着我们经验的增长,我们决定对此项目的屎山代码来一次彻底的重构
代码结构全面升级
优化包结构
逻辑处理做模块化设计 主类调用父类
加入并启用配置文件 如 : config.yml & plugin.yml
更改掉落逻辑 实现支持游戏内所有盒子以及保存盒子内部数据
同时兼容使用低版本jdk构建支持更多版本服务端
最终版不仅功能更完善,代码也更专业,真正达到了可发布、可维护的水平
同时让我们的代码质量不断提高 可读性不断优化 代码行数从几十行上升到上百行 <br
从第一版到最终版:我们学到了什么
团队协作的重要性
从最初的各写各的,到后来的分工明确、互相代码审查,我们的协作能力提升非常明显
代码质量不是一蹴而就的
第一版能跑,但有许多bug
最终版不仅能跑,还能维护、能扩展
具链的使用
- GitHub
- Issues
- Pull Request
- 版本管理
- 文档编写
这些都是我们在项目中真正学会的技能
代码展示
第一版
package hy.shulkerboxdrop;
import java.util.HashMap;
import java.util.Objects;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.block.BlockState;
import org.bukkit.block.ShulkerBox;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.PluginCommand;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BlockStateMeta;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.java.JavaPlugin;
public final class ShulkerBoxDrop extends JavaPlugin implements Listener {
private static final String PLUGIN_NAME = "[ShulkerBoxDrop]";
private PluginState pluginState;
private static final int SHULKER_BOX_BREAK_LIMIT = 10;
private final HashMap<UUID, Integer> shulkerBoxCount;
public ShulkerBoxDrop() {
this.pluginState = ShulkerBoxDrop.PluginState.ENABLED;
this.shulkerBoxCount = new HashMap();
}
//开关
public void onEnable() {
this.getServer().getPluginManager().registerEvents(this, this);
((PluginCommand)Objects.requireNonNull(this.getCommand("shulkerboxdrop"))).setExecutor(this);
Bukkit.getConsoleSender().sendMessage("[ShulkerBoxDrop]§aEnable");
}
public void onDisable() {
Bukkit.getConsoleSender().sendMessage("[ShulkerBoxDrop]§cDisable");
}
// 挖掘逻辑
private void dropShulkerBoxes(BlockBreakEvent event) {
UUID playerUUID = event.getPlayer().getUniqueId();
int count = (Integer)this.shulkerBoxCount.getOrDefault(playerUUID, 0);
++count;
if (count == 10) {
event.setDropItems(false);
BlockState blockState = event.getBlock().getState();
if (blockState instanceof ShulkerBox) {
ShulkerBox shulkerBox = (ShulkerBox)blockState;
Inventory inventory = shulkerBox.getInventory();
ItemStack itemStack = new ItemStack(event.getBlock().getType(), 2);
ItemMeta itemMeta = itemStack.getItemMeta();
if (itemMeta instanceof BlockStateMeta) {
BlockStateMeta blockStateMeta = (BlockStateMeta)itemMeta;
BlockState blockStateCopy = blockStateMeta.getBlockState();
if (blockStateCopy instanceof ShulkerBox) {
ShulkerBox shulkerBoxCopy = (ShulkerBox)blockStateCopy;
shulkerBoxCopy.getInventory().setContents(inventory.getContents());
blockStateMeta.setBlockState(shulkerBoxCopy);
itemStack.setItemMeta(blockStateMeta);
}
}
event.getBlock().getWorld().dropItemNaturally(event.getBlock().getLocation(), itemStack);
}
count = 0;
}
this.shulkerBoxCount.put(playerUUID, count);
}
@EventHandler
public void onBlockBreak(BlockBreakEvent event) {
if (this.pluginState == ShulkerBoxDrop.PluginState.ENABLED && event.getBlock().getType().isBlock()) {
this.dropShulkerBoxes(event);
}
}
//指令
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (command.getName().equalsIgnoreCase("shulkerboxdrop")) {
if (sender instanceof Player) {
this.pluginState = this.pluginState == ShulkerBoxDrop.PluginState.ENABLED ? ShulkerBoxDrop.PluginState.DISABLED : ShulkerBoxDrop.PluginState.ENABLED;
sender.sendMessage("[ShulkerBoxDrop] is now " + this.pluginState + ".");
} else {
sender.sendMessage("This command can only be used by players.");
}
return true;
} else {
return false;
}
}
private static enum PluginState {
ENABLED,
DISABLED;
}
}