新增功能:

- 增加了缓存文件 用于初始化时清理意外退出导致没被卸载的强加载区块

- 新增强加载半径配置

- 优化了日志输出

- 优化了实体清理机制

- 优化了一些代码
This commit is contained in:
张宇衡 2022-11-25 10:45:03 +08:00
parent e0685bf26b
commit 453b1ec72d
12 changed files with 294 additions and 21 deletions

View File

@ -48,6 +48,23 @@
`/loadanother status` 查看插件状态以及所有强加载区块列表。
`/loadanother setRadius <time>` 设置强加载半径。
```
半径图解 * 为玩家所在区块 + 为加载区块
1 : *
2 : + + +
+ * +
+ + +
3 : + + + + +
+ + + + +
+ + * + +
+ + + + +
+ + + + +
```
### 玩家指令

View File

@ -6,7 +6,7 @@
<groupId>deercloud</groupId>
<artifactId>LoadAnother</artifactId>
<version>1.0-SNAPSHOT</version>
<version>1.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>LoadAnother</name>

View File

@ -20,6 +20,13 @@ public class BindChunk {
m_state = State.FORCE;
}
public BindChunk(Chunk world, Chunk nether) {
creator = null;
m_world_chunk = world;
m_nether_chunk = nether;
hash = String.valueOf(m_world_chunk.getX()) + m_world_chunk.getZ() + m_nether_chunk.getX() + m_nether_chunk.getZ();
}
public boolean setDestination(Player player,Chunk to) {
if (player != creator) {
return false;
@ -29,9 +36,9 @@ public class BindChunk {
} else if (to.getWorld().getEnvironment() == World.Environment.NETHER) {
m_nether_chunk = to;
}
m_world_chunk.getWorld().setChunkForceLoaded(m_world_chunk.getX(), m_world_chunk.getZ(), true);
m_nether_chunk.getWorld().setChunkForceLoaded(m_nether_chunk.getX(), m_nether_chunk.getZ(), true);
hash = String.valueOf(m_world_chunk.getX()) + String.valueOf(m_world_chunk.getZ()) + String.valueOf(m_nether_chunk.getX()) + String.valueOf(m_nether_chunk.getZ());
setForceLoaded(true);
hash = String.valueOf(m_world_chunk.getX()) + m_world_chunk.getZ() + m_nether_chunk.getX() + m_nether_chunk.getZ();
m_cache.saveBindChunk(this);
return true;
}
@ -57,9 +64,15 @@ public class BindChunk {
}
public void unload() {
m_logger.warn(creator, "| 总共清理了" + clearChunkEntitiesByName(m_world_chunk, getHash()) + clearChunkEntitiesByName(m_nether_chunk, getHash()) + "个实体");
m_world_chunk.getWorld().setChunkForceLoaded(m_world_chunk.getX(), m_world_chunk.getZ(), false);
m_nether_chunk.getWorld().setChunkForceLoaded(m_nether_chunk.getX(), m_nether_chunk.getZ(), false);
m_world_chunk.load();
m_nether_chunk.load();
if (creator == null) {
m_logger.warn("| 总共清理了" + (clearChunkEntities(m_world_chunk) + clearChunkEntities(m_nether_chunk)) + "个实体");
}else{
m_logger.warn(creator, "| 总共清理了" + (clearChunkEntities(m_world_chunk) + clearChunkEntities(m_nether_chunk)) + "个实体");
}
setForceLoaded(false);
m_cache.removeBindChunk(this);
}
public boolean isContain(Chunk chunk) {
@ -81,9 +94,26 @@ public class BindChunk {
((Monster) entity).setRemoveWhenFarAway(true);
entity.remove();
((Monster) entity).setHealth(0);
number++;
}
}
}
return number;
}
// 清空一个区块中的敌对生物实体
public int clearChunkEntities(Chunk chunk) {
int number = 0;
for (Entity entity : chunk.getEntities()) {
if (entity instanceof Monster) {
String name_custom = entity.getCustomName();
if (!((Monster) entity).getRemoveWhenFarAway() && name_custom == null) {
((Monster) entity).setRemoveWhenFarAway(true);
entity.remove();
((Monster) entity).setHealth(0);
number++;
}
}
number++;
}
return number;
}
@ -109,6 +139,16 @@ public class BindChunk {
return m_nether_chunk;
}
private void setForceLoaded(boolean forceLoaded) {
int R = LoadAnother.getInstance().getConfigManager().getRadius() - 1;
for (int x = -R; x <= R; x++) {
for (int z = -R; z <= R; z++) {
m_world_chunk.getWorld().getChunkAt(m_world_chunk.getX() + x, m_world_chunk.getZ() + z).setForceLoaded(forceLoaded);
m_nether_chunk.getWorld().getChunkAt(m_nether_chunk.getX() + x, m_nether_chunk.getZ() + z).setForceLoaded(forceLoaded);
}
}
}
private final Player creator;
private Chunk m_world_chunk = null;
private Chunk m_nether_chunk = null;
@ -121,5 +161,6 @@ public class BindChunk {
}
MyLogger m_logger = LoadAnother.getInstance().getMyLogger();
Cache m_cache = LoadAnother.getInstance().getCache();
}

View File

@ -0,0 +1,97 @@
package deercloud.loadanother;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.util.List;
public class Cache {
public Cache(LoadAnother plugin) {
this.m_plugin = plugin;
reload();
}
public void reload() {
if (!isCacheFileExist()) {
createCacheFile();
}
m_cache_file = loadCacheFile();
}
// 创建缓存文件 cache.yml
public void createCacheFile() {
m_plugin.saveResource(".cache/cache.yml", false);
}
// 加载缓存文件 cache.yml
public YamlConfiguration loadCacheFile() {
return YamlConfiguration.loadConfiguration(new File(m_plugin.getDataFolder(), ".cache/cache.yml"));
}
// 检查是否存在缓存文件 cache.yml
public boolean isCacheFileExist() {
return m_plugin.getResource(".cache/cache.yml") != null;
}
public void saveCacheFile() {
try {
m_cache_file.save(new File(m_plugin.getDataFolder(), ".cache/cache.yml"));
} catch (Exception e) {
e.printStackTrace();
}
}
public void saveBindChunk(BindChunk bindChunk) {
Chunk m_world = bindChunk.getWorldChunk();
Chunk m_nether = bindChunk.getNetherChunk();
// chunk信息添加到yaml列表
List<String> chunk_info = m_cache_file.getStringList("chunk_info");
chunk_info.add(m_world.getX() + "," + m_world.getZ() + "," + m_nether.getX() + "," + m_nether.getZ());
m_cache_file.set("chunk_info", chunk_info);
saveCacheFile();
}
public int getCacheSize() {
return m_cache_file.getStringList("chunk_info").size();
}
public Chunk getWorldChunk(int index) {
String[] chunk_info = m_cache_file.getStringList("chunk_info").get(index).split(",");
return new Location(m_plugin.getServer().getWorld("world"), Integer.parseInt(chunk_info[0]), 0, Integer.parseInt(chunk_info[1])).getChunk();
}
public Chunk getNetherChunk(int index) {
String[] chunk_info = m_cache_file.getStringList("chunk_info").get(index).split(",");
return new Location(m_plugin.getServer().getWorld("world_nether"), Integer.parseInt(chunk_info[2]), 0, Integer.parseInt(chunk_info[3])).getChunk();
}
public void removeBindChunk(BindChunk bindChunk) {
Chunk m_world = bindChunk.getWorldChunk();
Chunk m_nether = bindChunk.getNetherChunk();
// chunk信息添加到yaml列表
List<String> chunk_info = m_cache_file.getStringList("chunk_info");
chunk_info.remove(m_world.getX() + "," + m_world.getZ() + "," + m_nether.getX() + "," + m_nether.getZ());
m_cache_file.set("chunk_info", chunk_info);
saveCacheFile();
}
public void removeBindChunk(int index) {
// chunk信息添加到yaml列表
List<String> chunk_info = m_cache_file.getStringList("chunk_info");
chunk_info.remove(index);
m_cache_file.set("chunk_info", chunk_info);
saveCacheFile();
}
LoadAnother m_plugin;
YamlConfiguration m_cache_file = null;
}

View File

@ -115,6 +115,7 @@ public class Commands implements TabExecutor {
if (player.isOp()) {
m_logger.info(player, "正在重载 LoadAnother 配置文件");
m_config_manager.reload();
m_work_manager.reset();
m_logger.info(player, "已重新加载 LoadAnother 配置文件");
} else {
m_logger.error(player, "你没有权限执行此命令");
@ -122,6 +123,7 @@ public class Commands implements TabExecutor {
} else {
sender.sendMessage(ChatColor.GREEN + "正在重载 LoadAnother 配置文件");
m_config_manager.reload();
m_work_manager.reset();
sender.sendMessage(ChatColor.GREEN + "已重新加载 LoadAnother 配置文件");
}
break;
@ -166,6 +168,8 @@ public class Commands implements TabExecutor {
m_logger.info(player,"| /loadanother status - 查看状态");
m_logger.info(player,"| /loadanother setLoadTime <整数> - 设置强加载持续时间0 代表不限制)");
m_logger.info(player,"| /loadanother setDelay <整数>- 设置玩家离开后卸载延迟时间");
m_logger.info(player,"| /loadanother setRadius <整数> - 设置加载区块半径");
m_logger.info(player,"| ===============================");
} else {
m_logger.info("| ===== LoadAnother 命令帮助 =====");
m_logger.info("| /loadanother help - 显示帮助");
@ -176,6 +180,8 @@ public class Commands implements TabExecutor {
m_logger.info("| /loadanother status - 查看状态");
m_logger.info("| /loadanother setLoadTime <整数> - 设置强加载持续时间0 代表不限制)");
m_logger.info("| /loadanother setDelay <整数>- 设置玩家离开后卸载延迟时间");
m_logger.info("| /loadanother setRadius <整数> - 设置加载区块半径");
m_logger.info("| ===============================");
}
}
@ -191,7 +197,7 @@ public class Commands implements TabExecutor {
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
if (args.length == 1) {
return Arrays.asList("help", "reload", "enable", "disable", "setLoadTime", "setDelay", "status");
return Arrays.asList("help", "reload", "enable", "disable", "setLoadTime", "setDelay", "setRadius", "status");
} else if (args.length == 2) {
if (args[0].equals("setLoadTime")) {
return Collections.singletonList("请输入整数 (单位:秒) 设置强加载持续时间0为不限制");
@ -199,6 +205,9 @@ public class Commands implements TabExecutor {
if (args[0].equals("setDelay")) {
return Collections.singletonList("请输入整数 (单位:秒) 设置玩家离开后延迟卸载时间0为立即卸载");
}
if (args[0].equals("setRadius")) {
return Collections.singletonList("请输入整数 (单位:区块) 设置加载区块半径");
}
}
return null;
}

View File

@ -16,11 +16,28 @@ public class ConfigManager {
m_config_file = m_plugin.getConfig();
m_enable = m_config_file.getBoolean("enable", true);
m_load_time = m_config_file.getInt("loadTime", 0);
if (m_load_time < 0) {
m_load_time = 0;
setLoadTime(m_load_time);
m_logger.warn("loadTime 不能小于0已经自动调整为0。");
}
m_delay = m_config_file.getInt("delay", 0);
if (m_delay < 0) {
m_delay = 0;
setDelay(m_delay);
m_logger.warn("延迟时间不能小于0已经自动调整为0。");
}
m_radius = m_config_file.getInt("radius", 1);
if (m_radius < 1) {
m_radius = 1;
setRadius(m_radius);
m_logger.warn("radius 不能小于1已重置为默认值 1");
}
m_logger.info("加载配置文件完成");
m_logger.info(" - 是否启用功能 " + m_enable);
m_logger.info(" - 加载持续时间 " + m_load_time + "0 代表不限制)");
m_logger.info(" - 延迟卸载时间 " + m_delay + "");
m_logger.info(" - 强加载半径为 " + m_radius + "区块");
}
public boolean getEnable() {
@ -36,6 +53,9 @@ public class ConfigManager {
return m_load_time;
}
public void setLoadTime(int load_time) {
if (load_time < 0) {
load_time = 0;
}
m_load_time = load_time;
m_config_file.set("loadTime", load_time);
m_plugin.saveConfig();
@ -44,10 +64,24 @@ public class ConfigManager {
return m_delay;
}
public void setDelay(int delay) {
if (delay < 0) {
delay = 0;
}
m_delay = delay;
m_config_file.set("delay", delay);
m_plugin.saveConfig();
}
public int getRadius() {
return m_radius;
}
public void setRadius(int radius) {
if (radius < 1) {
radius = 1;
}
m_radius = radius;
m_config_file.set("radius", radius);
m_plugin.saveConfig();
}
private final LoadAnother m_plugin;
private final MyLogger m_logger;
@ -56,5 +90,6 @@ public class ConfigManager {
private boolean m_enable = false;
private int m_load_time = 0;
private int m_delay = 0;
private int m_radius = 1;
}

View File

@ -10,6 +10,7 @@ import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerPortalEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.world.ChunkUnloadEvent;
import org.bukkit.event.world.WorldLoadEvent;
public class Events implements Listener {
@ -33,6 +34,11 @@ public class Events implements Listener {
m_work.playerJoinController(event.getPlayer());
}
@EventHandler
public void onWorldLoaded(WorldLoadEvent event) {
m_work.resetPending();
}
WorkManager m_work = LoadAnother.getInstance().getWorkManager();
}

View File

@ -10,6 +10,7 @@ public final class LoadAnother extends JavaPlugin {
public void onEnable() {
// Plugin startup logic
instance = this;
m_cache = new Cache(this);
m_logger = new MyLogger(this);
m_config = new ConfigManager(this);
m_work = new WorkManager(this);
@ -19,6 +20,8 @@ public final class LoadAnother extends JavaPlugin {
// 注册命令
Objects.requireNonNull(getCommand("loadanother")).setExecutor(new Commands());
m_work.reset();
m_logger.info("LoadAnother 启动完成");
}
@ -44,8 +47,14 @@ public final class LoadAnother extends JavaPlugin {
return instance;
}
public Cache getCache() {
return m_cache;
}
private ConfigManager m_config = null;
private MyLogger m_logger = null;
private WorkManager m_work = null;
private static LoadAnother instance = null;
private Cache m_cache = null;
}

View File

@ -8,12 +8,11 @@ import java.util.logging.Logger;
public class MyLogger {
public MyLogger(LoadAnother plugin) {
this.m_plugin = plugin;
m_logger = m_plugin.getLogger();
m_logger = plugin.getLogger();
}
public void info(Player player, String msg) {
m_logger.info(ChatColor.GREEN + msg);
m_logger.info(ChatColor.GREEN + "[ 来自玩家:" + player.getName() + " ]" +msg);
player.sendMessage(ChatColor.GREEN + msg);
}
public void info(String msg) {
@ -21,7 +20,7 @@ public class MyLogger {
}
public void warn(Player player, String msg) {
m_logger.warning(ChatColor.YELLOW + msg);
m_logger.warning(ChatColor.YELLOW + "[ 来自玩家:" + player.getName() + " ]" + msg);
player.sendMessage(ChatColor.YELLOW + msg);
}
public void warn(String msg) {
@ -29,14 +28,13 @@ public class MyLogger {
}
public void error(Player player, String msg) {
m_logger.severe(ChatColor.RED + msg);
m_logger.severe(ChatColor.RED + "[ 来自玩家:" + player.getName() + " ]" + msg);
player.sendMessage(ChatColor.RED + msg);
}
public void error(String msg) {
m_logger.severe(ChatColor.RED + msg);
}
private LoadAnother m_plugin = null;
private Logger m_logger = null;
private final Logger m_logger;
}

View File

@ -1,5 +1,6 @@
package deercloud.loadanother;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Chunk;
import org.bukkit.World;
@ -9,8 +10,11 @@ import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityPortalEnterEvent;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerPortalEvent;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@ -60,6 +64,7 @@ public class WorkManager {
m_logger.info(player, "| 编号 - " + bind_chunk.getHash());
m_logger.info(player, "| | 主世界区块 " + bind_chunk.getWorldChunk().getX() + ", " + bind_chunk.getWorldChunk().getZ());
m_logger.info(player, "| | 下届区块为 " + bind_chunk.getNetherChunk().getX() + ", " + bind_chunk.getNetherChunk().getZ());
m_logger.info(player, "| ======================");
}
public void playerPortalController(PlayerPortalEvent event) {
@ -84,10 +89,10 @@ public class WorkManager {
public void playerJoinController(Player player) {
if (m_config.getEnable()) {
playerEnable(player);
m_logger.info(player, ChatColor.GREEN + "| 强加载已开启 使用 /loadanother help 查看帮助");
m_logger.info(player, "| 强加载已开启 使用 /loadanother help 查看帮助");
} else {
playerDisable(player);
m_logger.info(player, ChatColor.RED + "| 强加载已关闭 使用 /loadanother help 查看帮助");
m_logger.info(player, "| 强加载已关闭 使用 /loadanother help 查看帮助");
}
}
@ -103,7 +108,7 @@ public class WorkManager {
if (bind_chunk == null) {
return;
}
monster.setCustomName(bind_chunk.getHash());
// monster.setCustomName(bind_chunk.getHash());
monster.setRemoveWhenFarAway(false);
}
@ -213,6 +218,7 @@ public class WorkManager {
m_logger.info(player, "| 强加载状态: " + (player_setting.get(player) ? "开启" : "关闭"));
m_logger.info(player, "| 强加载持续时间: " + m_config.getLoadTime() + "0 代表不限制)");
m_logger.info(player, "| 强加载延迟卸载时间: " + m_config.getDelay() + "");
m_logger.info(player, "| 强加载区块半径: " + m_config.getRadius());
m_logger.info(player, "| =====强加载内容=====");
for (Map.Entry<String , BindChunk> entry : m_bind_chunks.entrySet()) {
BindChunk bind_chunk = entry.getValue();
@ -220,10 +226,12 @@ public class WorkManager {
m_logger.info(player, "| 强加载区块Hash " + bind_chunk.getHash());
m_logger.info(player, "| 主世界区块坐标 " + bind_chunk.getWorldChunk().getX() + ", " + bind_chunk.getWorldChunk().getZ());
m_logger.info(player, "| 地狱侧区块坐标 " + bind_chunk.getNetherChunk().getX() + ", " + bind_chunk.getNetherChunk().getZ());
m_logger.info(player, "| ===================");
return;
}
}
m_logger.info(player, "| 无,使用地狱门跳跃后可查看");
m_logger.info(player, "| ===================");
}
public void printStatusOP(CommandSender sender) {
@ -233,6 +241,7 @@ public class WorkManager {
m_logger.info(player, "| 默认强加载状态: " + (m_config.getEnable() ? "开启" : "关闭"));
m_logger.info(player, "| 强加载持续时间: " + m_config.getLoadTime() + "0 代表不限制)");
m_logger.info(player, "| 强加载延迟卸载时间: " + m_config.getDelay() + "");
m_logger.info(player, "| 强加载区块半径: " + m_config.getRadius());
m_logger.info(player, "| =====强加载区块列表=====");
for (Map.Entry<String, BindChunk> entry : m_bind_chunks.entrySet()) {
BindChunk bind_chunk = entry.getValue();
@ -240,6 +249,7 @@ public class WorkManager {
m_logger.info(player, "| | World : " + bind_chunk.getWorldChunk().getX() + ", " + bind_chunk.getWorldChunk().getZ());
m_logger.info(player, "| | Nether: " + bind_chunk.getNetherChunk().getX() + ", " + bind_chunk.getNetherChunk().getZ());
}
m_logger.info(player, "| ===================");
} else {
m_logger.info("| =====插件配置=====");
m_logger.info("| 默认强加载状态: " + (m_config.getEnable() ? "开启" : "关闭"));
@ -253,6 +263,39 @@ public class WorkManager {
m_logger.info("| | Nether: " + bind_chunk.getNetherChunk().getX() + ", " + bind_chunk.getNetherChunk().getZ());
}
}
m_logger.info("| ===================");
}
public void reset() {
isReseting = true;
// 获取所有在线玩家
ArrayList<Player> players = new ArrayList<>(Bukkit.getOnlinePlayers());
for (Player player : players) {
player_setting.put(player, m_config.getEnable());
}
}
public void resetPending() {
if (!isReseting) {
return ;
}
if (m_plugin.getServer().getWorld("world") == null || m_plugin.getServer().getWorld("world_nether") == null) {
return ;
}
isReseting = false;
m_bind_chunks.clear();
teleport_cache.clear();
int count;
Cache cache = m_plugin.getCache();
cache.reload();
for (count = 0; count < cache.getCacheSize(); count++) {
Chunk world_chunk = cache.getWorldChunk(count);
Chunk nether_chunk = cache.getNetherChunk(count);
BindChunk bind_chunk = new BindChunk(world_chunk, nether_chunk);
bind_chunk.unload();
cache.removeBindChunk(count);
}
m_logger.info("初始化清理了意外退出的未卸载强加载区块" + count + "个。");
}
LoadAnother m_plugin;
@ -267,4 +310,6 @@ public class WorkManager {
// 保存玩家设置
Map<Player, Boolean> player_setting = new HashMap<>();
private boolean isReseting = false;
}

View File

View File

@ -2,7 +2,23 @@
enable: true
# 强加载持续时间 单位0 为不限制 直到玩家离开)
loadTime: 600
loadTime: 0
# 玩家离开后卸载的延时 单位0 为立即卸载)
delay: 20
delay: 20
# 强加载半径
radius: 1
# 例如
# 1 : +
# 2 : + + +
# + + +
# + + +
# 3 : + + + + +
# + + + + +
# + + + + +
# + + + + +
# + + + + +