Я действительно не знаю, что имел в виду этот парень, но у меня есть надежное решение для вас.
Прежде всего я сообщу вам о том, что происходит, когда вы не можете new DataManager(event.getPlayer())
:
В основном Java копирует копию вашего public class DataManager
и сохраняет ее в оперативной памяти, а затем выполняет ваши задачи.Поскольку это бесполезно, когда вы просто используете новый экземпляр для одной задачи (например, сохраняете или загружаете данные), вы можете просто создавать статические функции и запускать их асинхронно, чтобы они не блокировали основной поток Bukkit.Идея состоит в том, чтобы создать файл .lock
до тех пор, пока данные записываются, и читать данные только после удаления файла .lock
.
public static void saveData(Player player) throws IOException {
File locker = new File(YOUR_PATH_TO_CONFIG + player.getUniqueId() + ".lock");
locker.createNewFile(); //create locker-file
Bukkit.getServer().getScheduler().runTaskAsynchronously(plugin, () -> {
try {
ConfigManager configmanager = new ConfigManager(player.getUniqueId());
FileConfiguration config = configmanager.getConfig();
config.set("Contents", player.getInventory().getContents());
config.set("Enderchest", player.getEnderChest().getContents());
config.set("Armor", player.getInventory().getArmorContents());
config.set("Effects", player.getActivePotionEffects());
config.set("Health", player.getHealth());
config.set("Experience", player.getExp());
config.set("Food", player.getFoodLevel());
configmanager.saveConfig();
} catch (IOException ex) {
// TODO: handle exception
}
locker.delete(); //delete the locker-file so the new server can access the playerdata
});
}
public static void loadData(Player player) {
Bukkit.getServer().getScheduler().runTaskAsynchronously(plugin, () -> { //run async to not block the main thread
File f = new File(YOUR_PATH_TO_CONFIG + player.getUniqueId() + ".lock");
while (f.exists()) { //as long as the locker-file exists we want to wait
try {
Thread.sleep(50); //wait one minecraft-tick
} catch (InterruptedException ignored) {}
}
Bukkit.getScheduler().runTask(plugin, () -> { //run sync
FileConfiguration config = new ConfigManager(player.getUniqueId()).getConfig();
player.getInventory().setContents(Arrays.asList((List<ItemStack>) config.get("Contents")).toArray(new ItemStack[0]));
player.getEnderChest().setContents(((List<ItemStack>) config.get("Enderchest")).toArray(new ItemStack[0]));
player.getInventory().setArmorContents(((List<ItemStack>) config.get("Armor")).toArray(new ItemStack[0]));
player.addPotionEffects((Collection<PotionEffect>) config.get("Effects"));
player.setHealth(config.getDouble("Health"));
player.setExp((float) config.getDouble("Experience"));
player.setFoodLevel(config.getInt("Food"));
});
});
}
Заменить YOUR_PATH_TO_CONFIG
местом, в которое вы записываете данные.сохраните настройки проигрывателя.
Теперь вы должны изменить ваши события на это:
@EventHandler(priority = EventPriority.MONITOR)
public void onJoin(PlayerJoinEvent event) {
DataManager.loadData(event.getPlayer());
}
@EventHandler(priority = EventPriority.LOWEST)
public void onQuit(PlayerQuitEvent event) throws IOException {
DataManager.saveData(event.getPlayer());
}
Я установил приоритет QuitEvent на LOWEST, чтобы он вызывался первым (событиедо того, как сервер присоединится к новому серверу) и JoinEvent to MONITOR, чтобы он наконец вызывался, когда игрок уже присоединился.
Я не полностью тестировал это несколько раз и с задержками на сервере, но до сих пор это работало.Если это не сработает, вам стоит подумать об использовании bungeecords Plugin Messaging Channel
.https://www.spigotmc.org/wiki/bukkit-bungee-plugin-messaging-channel/ Там вы можете отправить полный инвентарь через плагин-сообщение на BungeeCord, а затем отправить его на следующий сервер, к которому присоединяется игрок.Просто убедитесь, что игрок может присоединиться к новому серверу, только когда сообщение о плагине было полностью получено вашим сервером BungeeCord.Но это действительно опытное программирование, и я не рекомендовал бы его вам, если вы только начали программировать, поскольку это доставит вам некоторую головную боль (просто спросите stackoverflow)
Возможно, более простое и надежное исправление вашего проблема параллелизма состоит в том, чтобы не позволить игроку присоединиться к другому серверу в течение примерно 5 секунд, чтобы он оставался в лобби во время сохранения данных.
Все это были только рекомендации, и я надеюсь, чтоПервый фрагмент кода, который я разместил здесь, работает.Если что-то не работает, просто спросите меня лично.Я постараюсь помочь вам в дальнейшем.