Войти или зарегистрироваться
  • Вы находитесь в сообществе Rubukkit. Мы - администраторы серверов Minecraft, разрабатываем собственные плагины и переводим на различные языки плагины наших коллег из других стран.

Помогите Пропадает информация в Entity

Статус
Закрыто для дальнейших ответов.

Loltik

Активный участник
Пользователь
Баллы
66
Имя в Minecraft
Mitriyf
Сохраняю данные MetaData или getPersistentDataContainer в сущность, итог один. Работает, но если игрок уйдёт из чанка с боссом или умрёт рядом с ним, то MetaData или getPersistentDataContainer будет очищено.

Есть ли замена или способы решения проблемы?

Paper 1.19.4, Java
 
Код спавна босса:

public String key = "jumpbosses";

LivingEntity boss12 = (LivingEntity) boss2.getLocation().getWorld().spawnEntity(boss2.getLocation(), boss2.getType());
boss12.setCanPickupItems(false);
boss12.setMaxHealth((double) boss2.getHealth());
boss12.setHealth((double) boss2.getHealth());
boss12.setCustomName(boss2.getName());
boss12.setRemoveWhenFarAway(true);
boss12.setCustomNameVisible(true);
boss12.setGlowing(true);

if (boss12.getType() == EntityType.ZOMBIE) {
((Zombie) boss12).setBaby(false);
}

AttributeInstance attr = boss12.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED);
attr.addModifier(new AttributeModifier("GENERIC_MOVEMENT_SPEED", attr.getBaseValue() * configuration.getInt("bosses." + id + ".move") - attr.getBaseValue(), AttributeModifier.Operation.ADD_NUMBER));
AttributeInstance attr2 = boss12.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE);
attr2.setBaseValue(attr2.getBaseValue() * configuration.getInt("bosses." + id + ".damage"));

boss12.setMetadata(key, new FixedMetadataValue(this, ladno));
 
Метадата не сохраняется на диск, сохраняется только персистент дата контейнер.

Проблема у тебя не в сохранении персистент даты, а в сохранении моба на диск.
Ядро в принципе не сохраняет на диск враждебных мобов. Поэтому на всяких фермах на мобов применяют бирку.
Чтобы моб принудительно сохранялся на диск - используй entity.setPersistent(true).

Но после этого ты, скорее всего, столкнешься с другой проблемой - дублирование мобов. Ядро будет загружать старого моба с датой, а ты своим кодом будешь спаунить ещё одного, нового. Что с этим делать - решай сам
 
Метадата не сохраняется на диск, сохраняется только персистент дата контейнер.

Проблема у тебя не в сохранении персистент даты, а в сохранении моба на диск.
Ядро в принципе не сохраняет на диск враждебных мобов. Поэтому на всяких фермах на мобов применяют бирку.
Чтобы моб принудительно сохранялся на диск - используй entity.setPersistent(true).

Но после этого ты, скорее всего, столкнешься с другой проблемой - дублирование мобов. Ядро будет загружать старого моба с датой, а ты своим кодом будешь спаунить ещё одного, нового. Что с этим делать - решай сам
А есть ли замена способу? entity.setPersistent(true) вроде пробовал не помогло, но сейчас ещё раз проверю.
 
Я проверил, он не дублирует, но Metadata всё равно пропадает. Сейчас попробую персистент дата контейнер
 
Такая же ситуация. Ничего не сохраняется и не дублируется при выходе из чанка на некоторое время.
 
Такая же ситуация. Ничего не сохраняется и не дублируется при выходе из чанка на некоторое время.
Убедись, что у тебя действительно одна и та же сущность каждый раз. Для этого можно просто UUID отобразить где-либо.
И покажи код, где у тебя вызывается спаун сущности
 
public void spawnBoss2() {
this.damageList = null;
String id = this.options[this.random.nextInt(this.options.length)].replace("\"", "");
Boss boss2 = Configs.MAIN_CONFIG.getBossById(id);
boss2.getLocation().getChunk().load();
LivingEntity boss12 = (LivingEntity)boss2.getLocation().getWorld().spawnEntity(boss2.getLocation(), boss2.getType());
boss12.setCanPickupItems(false);
boss12.setMaxHealth((double)boss2.getHealth());
boss12.setHealth((double)boss2.getHealth());
boss12.setCustomName(boss2.getName());
boss12.setRemoveWhenFarAway(false);
boss12.setCustomNameVisible(true);
boss12.setGlowing(true);
String ladno = boss2.getId() + random.nextInt(1000000);
boss12.getPersistentDataContainer().set(key, PersistentDataType.STRING, ladno);
boss12.setPersistent(true);

if (boss12.getType() == EntityType.ZOMBIE) {
((Zombie)boss12).setBaby(false);
}
get2.add(boss12.getCustomName());
get3.add(id);
BossBar bossBar1 = this.getServer().createBossBar(ColorHelper.colorize(Configs.MAIN_CONFIG.getBossbar().replace("%name%", boss2.getName()).replace("%health%", String.valueOf(Math.round(boss12.getHealth())))), boss2.getColor(), BarStyle.SEGMENTED_12, new BarFlag[0]);
bossBar1.setVisible(true);
bossBar1.setProgress(1.0D);
boss12.setPersistent(true);
boss12.getWorld().spawnParticle(Particle.CRIT, boss12.getLocation(), 50, 1, 1, 1, 0.1);
boss12.getWorld().spawnParticle(Particle.ENCHANTMENT_TABLE, boss12.getLocation(), 30, 1, 1, 1, 0.1);
boss12.getWorld().spawnParticle(Particle.FIREWORKS_SPARK, boss12.getLocation(), 20, 1, 1, 1, 0.1);
Bukkit.getLogger().warning(ladno);
bossBar.put(ladno, bossBar1);
this.getServer().getOnlinePlayers().forEach((player) -> {
Lang.SPAWNED.send(player, new Pair("%id%", boss2.getId()), new Pair("%name%", boss2.getName()));
bossBar1.addPlayer(player);
});
YamlConfiguration configuration = ConfigManager.of("settings.yml").getYamlConfiguration();
AttributeInstance attr = boss12.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED);
attr.addModifier(new AttributeModifier("GENERIC_MOVEMENT_SPEED", attr.getBaseValue() * configuration.getInt("bosses." + id + ".move"), AttributeModifier.Operation.ADD_NUMBER));
AttributeInstance attr2 = boss12.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE);
attr2.setBaseValue(attr2.getBaseValue() * configuration.getInt("bosses." + id + ".damage"));
boss.put(boss12, boss2);
if (configuration.getBoolean("bosses." + id + ".spheres") == true) {
Spheres(boss12, boss2.getName(), ladno);
}
BukkitTask task = this.getServer().getScheduler().runTaskTimer(this, () -> {
if (boss2 != null) {
List<Entry<String, Integer>> damageList = Handler.getSortedDamageList();
this.getServer().getOnlinePlayers().forEach((player) -> {
Optional<Entry<String, Integer>> entryOptional = damageList.stream().filter((entry) -> {
return ((String)entry.getKey()).equals(player.getName());
}).findFirst();
entryOptional.ifPresent((uuidIntegerEntry) -> {
player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(ColorHelper.colorize(Configs.MAIN_CONFIG.getActionBar().replace("%index%", String.valueOf(damageList.indexOf(uuidIntegerEntry) + 1)).replace("%max%", String.valueOf(damageList.size())).replace("%damage%", String.valueOf(uuidIntegerEntry.getValue())))));
});
});
}

}, 0L, 40L);
tasks.put(ladno, task);
}

Код спавна.

Сейчас проверю по UUID
 
UUID не меняется, кстати ты мне подсказал одну идею. Возможно сейчас проверю, вдруг сработает.
 
Я бы рекомендовал для начала привести порядок в код. Сейчас всё в куче, очень легко запутаться, что-то упустить или перепутать. Я, честно говоря, поначалу я вообще не понял, что происходит в коде. Чуть привёл в порядок, стало яснее.

Но до сих пор некоторые моменты непонятны - например, где вызывается метод spawnBoss2()? Разны ли String id и boss.getId()? Существует несколько методов спауна боссов? Чем они отличаются между собой? Они между собой не конфликтуют из-за общих мап? Например, из-за "get3.add(id);".
Вопросы риторические, отвечать не нужно, главное разберись сам.

Короче говоря, скорее всего, проблема у тебя не в сохранении persistent data container, а именно в логике твоего кода. Либо метод не вызывается, либо вызывается не для той сущности, либо не в нужный момент, либо ты ошибся при выводе UUID, либо что-то ещё. Тем более отрефакторить будет полезно, если у тебя больше одного вида боссов.

Сам по себе persistent data container работает идеально, если с ядром всё в порядке. Поэтому убедись, что у тебя последний билд Paper для 1.19.4.

- Удалил явную загрузку чанка. Ядро само сделает это при необходимости
- В шедулере удалил проверку if(boss2 != null), поскольку переменная никогда не будет нулл
- Мапу boss переименовал в bossEntities, а переменную boss2 просто в boss
- Мапу bossBar переименовал в bossBars, а переменную bossBar1 просто в bossBar
- Переименовал остальные локальные переменные метода, чтобы увеличить читабельность
- Заменил некоторые устаревшие методы Paper API на актуальные
- Разделил код на логические методы
PHP:
public void spawnBoss2() {
    this.damageList = null;

    String configBossId = getRandomBossConfigId();

    Boss boss = Configs.MAIN_CONFIG.getBossById(configBossId);

    String randomBossId = boss.getId() + random.nextInt(1000000);
    this.getLogger().warning(randomBossId);

    LivingEntity bossEntity = this.createBossEntity(boss, configBossId);
    this.displayBossEntity(boss, bossEntity);
    this.applyBossSpheres(boss, bossEntity, configBossId, randomBossId);

    bossEntity.getPersistentDataContainer().set(key, PersistentDataType.STRING, randomBossId);

    bossEntities.put(bossEntity, boss);
    get2.add(bossEntity.getCustomName());
    get3.add(configBossId);

    BossBar bossBar = this.createBossBar(boss, bossEntity);
    bossBars.put(randomBossId, bossBar);

    BukkitTask task = this.getServer().getScheduler().runTaskTimer(this, this::broadcastBossStatus, 0L, 40L);
    tasks.put(randomBossId, task);
}

private String getRandomBossConfigId() {
    return this.options[this.random.nextInt(this.options.length)].replace("\"", "");
}

private LivingEntity createBossEntity(Boss boss, String configBossId) {
    LivingEntity bossEntity = (LivingEntity) boss.getLocation().getWorld().spawnEntity(boss.getLocation(), boss.getType());

    this.applyAttributes(bossEntity, boss, configBossId);

    bossEntity.setCanPickupItems(false);
    bossEntity.setCustomName(boss.getName());
    bossEntity.setRemoveWhenFarAway(false);
    bossEntity.setCustomNameVisible(true);
    bossEntity.setGlowing(true);
    bossEntity.setPersistent(true);

    if (bossEntity instanceof Zombie zombie) {
        zombie.setAdult();
    }

    return bossEntity;
}

private void applyAttributes(LivingEntity bossEntity, Boss boss, String configBossId) {
    YamlConfiguration configuration = ConfigManager.of("settings.yml").getYamlConfiguration();

    AttributeInstance speed = bossEntity.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED);
    if (speed != null) {
        speed.addModifier(new AttributeModifier(
                "GENERIC_MOVEMENT_SPEED",
                speed.getBaseValue() * configuration.getInt("bosses." + configBossId + ".move"),
                AttributeModifier.Operation.ADD_NUMBER
        ));
    }

    AttributeInstance maxHealth = bossEntity.getAttribute(Attribute.GENERIC_MAX_HEALTH);
    if (maxHealth != null) {
        double health = boss.getHealth();
        maxHealth.setBaseValue(health);
        bossEntity.setHealth(health);
    }

    AttributeInstance damage = bossEntity.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE);
    if (damage != null) {
        damage.setBaseValue(damage.getBaseValue() * configuration.getInt("bosses." + configBossId + ".damage"));
    }
}

private void applyBossSpheres(Boss boss, LivingEntity bossEntity, String configBossId, String randomBossId) {
    if (configuration.getBoolean("bosses." + configBossId + ".spheres") == true) {
        Spheres(bossEntity, boss.getName(), randomBossId);
    }
}

private BossBar createBossBar(Boss boss, LivingEntity bossEntity) {
    BossBar bar = Bukkit.createBossBar(ColorHelper.colorize(
            Configs.MAIN_CONFIG.getBossbar()
                    .replace("%name%", boss.getName())
                    .replace("%health%", String.valueOf(Math.round(bossEntity.getHealth())))
    ), boss.getColor(), BarStyle.SEGMENTED_12, new BarFlag[0]);

    bar.setVisible(true);
    bar.setProgress(1.0D);

    Bukkit.getOnlinePlayers().forEach(bar::addPlayer);
    return bar;
}

private void displayBossEntity(Boss boss, LivingEntity bossEntity) {
    Location location = bossEntity.getLocation();
    World world = location.getWorld();

    world.spawnParticle(Particle.CRIT,
            location, 50, 1, 1, 1, 0.1);
    world.spawnParticle(Particle.ENCHANTMENT_TABLE,
            location, 30, 1, 1, 1, 0.1);
    world.spawnParticle(Particle.FIREWORKS_SPARK,
            location, 20, 1, 1, 1, 0.1);

    for (Player player : Bukkit.getOnlinePlayers()) {
        Lang.SPAWNED.send(player,
                new Pair("%id%", boss.getId()),
                new Pair("%name%", boss.getName())
        );
    }
}

private void broadcastBossStatus() {
    Server server = Bukkit.getServer();

    List<Map.Entry<String, Integer>> damageList = Handler.getSortedDamageList();
    for (int index = 0; index < damageList.size(); index++) {
        Map.Entry<String, Integer> entry = damageList.get(index);

        String playerName = entry.getKey();
        Player player = server.getPlayer(playerName);
        if (player == null) continue;

        int damage = entry.getValue();

        Component actionBar = Component.text(
                Configs.MAIN_CONFIG.getActionBar()
                        .replace("%index%", String.valueOf(index + 1))
                        .replace("%max%", String.valueOf(damageList.size()))
                        .replace("%damage%", String.valueOf(damage))
        );
        player.sendActionBar(actionBar);
    }
}

И на будущее - код вставлять лучше вот так:
upload_2023-12-22_16-24-12.png
В качестве языка выбирай PHP, у него лучше всего подсветка. Получится так же, как под мои спойлером
 
Последнее редактирование:
Я бы рекомендовал для начала привести порядок в код. Сейчас всё в куче, очень легко запутаться, что-то упустить или перепутать. Я, честно говоря, поначалу я вообще не понял, что происходит в коде. Чуть привёл в порядок, стало яснее.

Но до сих пор некоторые моменты непонятны - например, где вызывается метод spawnBoss2()? Разны ли String id и boss.getId()? Существует несколько методов спауна боссов? Чем они отличаются между собой? Они между собой не конфликтуют из-за общих мап? Например, из-за "get3.add(id);".
Вопросы риторические, отвечать не нужно, главное разберись сам.

Короче говоря, скорее всего, проблема у тебя не в сохранении persistent data container, а именно в логике твоего кода. Либо метод не вызывается, либо вызывается не для той сущности, либо не в нужный момент, либо ты ошибся при выводе UUID, либо что-то ещё. Тем более отрефакторить будет полезно, если у тебя больше одного вида боссов.

Сам по себе persistent data container работает идеально, если с ядром всё в порядке. Поэтому убедись, что у тебя последний билд Paper для 1.19.4.

- Удалил явную загрузку чанка. Ядро само сделает это при необходимости
- В шедулере удалил проверку if(boss2 != null), поскольку переменная никогда не будет нулл
- Мапу boss переименовал в bossEntities, а переменную boss2 просто в boss
- Мапу bossBar переименовал в bossBars, а переменную bossBar1 просто в bossBar
- Переименовал остальные локальные переменные метода, чтобы увеличить читабельность
- Заменил некоторые устаревшие методы Paper API на актуальные
- Разделил код на логические методы
PHP:
public void spawnBoss2() {
    this.damageList = null;

    String configBossId = getRandomBossConfigId();

    Boss boss = Configs.MAIN_CONFIG.getBossById(configBossId);

    String randomBossId = boss.getId() + random.nextInt(1000000);
    this.getLogger().warning(randomBossId);

    LivingEntity bossEntity = this.createBossEntity(boss, configBossId);
    this.displayBossEntity(boss, bossEntity);
    this.applyBossSpheres(boss, bossEntity, configBossId, randomBossId);

    bossEntity.getPersistentDataContainer().set(key, PersistentDataType.STRING, randomBossId);

    bossEntities.put(bossEntity, boss);
    get2.add(bossEntity.getCustomName());
    get3.add(configBossId);

    BossBar bossBar = this.createBossBar(boss, bossEntity);
    bossBars.put(randomBossId, bossBar);

    BukkitTask task = this.getServer().getScheduler().runTaskTimer(this, this::broadcastBossStatus, 0L, 40L);
    tasks.put(randomBossId, task);
}

private String getRandomBossConfigId() {
    return this.options[this.random.nextInt(this.options.length)].replace("\"", "");
}

private LivingEntity createBossEntity(Boss boss, String configBossId) {
    LivingEntity bossEntity = (LivingEntity) boss.getLocation().getWorld().spawnEntity(boss.getLocation(), boss.getType());

    this.applyAttributes(bossEntity, boss, configBossId);

    bossEntity.setCanPickupItems(false);
    bossEntity.setCustomName(boss.getName());
    bossEntity.setRemoveWhenFarAway(false);
    bossEntity.setCustomNameVisible(true);
    bossEntity.setGlowing(true);
    bossEntity.setPersistent(true);

    if (bossEntity instanceof Zombie zombie) {
        zombie.setAdult();
    }

    return bossEntity;
}

private void applyAttributes(LivingEntity bossEntity, Boss boss, String configBossId) {
    YamlConfiguration configuration = ConfigManager.of("settings.yml").getYamlConfiguration();

    AttributeInstance speed = bossEntity.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED);
    if (speed != null) {
        speed.addModifier(new AttributeModifier(
                "GENERIC_MOVEMENT_SPEED",
                speed.getBaseValue() * configuration.getInt("bosses." + configBossId + ".move"),
                AttributeModifier.Operation.ADD_NUMBER
        ));
    }

    AttributeInstance maxHealth = bossEntity.getAttribute(Attribute.GENERIC_MAX_HEALTH);
    if (maxHealth != null) {
        double health = boss.getHealth();
        maxHealth.setBaseValue(health);
        bossEntity.setHealth(health);
    }

    AttributeInstance damage = bossEntity.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE);
    if (damage != null) {
        damage.setBaseValue(damage.getBaseValue() * configuration.getInt("bosses." + configBossId + ".damage"));
    }
}

private void applyBossSpheres(Boss boss, LivingEntity bossEntity, String configBossId, String randomBossId) {
    if (configuration.getBoolean("bosses." + configBossId + ".spheres") == true) {
        Spheres(bossEntity, boss.getName(), randomBossId);
    }
}

private BossBar createBossBar(Boss boss, LivingEntity bossEntity) {
    BossBar bar = Bukkit.createBossBar(ColorHelper.colorize(
            Configs.MAIN_CONFIG.getBossbar()
                    .replace("%name%", boss.getName())
                    .replace("%health%", String.valueOf(Math.round(bossEntity.getHealth())))
    ), boss.getColor(), BarStyle.SEGMENTED_12, new BarFlag[0]);

    bar.setVisible(true);
    bar.setProgress(1.0D);

    Bukkit.getOnlinePlayers().forEach(bar::addPlayer);
    return bar;
}

private void displayBossEntity(Boss boss, LivingEntity bossEntity) {
    Location location = bossEntity.getLocation();
    World world = location.getWorld();

    world.spawnParticle(Particle.CRIT,
            location, 50, 1, 1, 1, 0.1);
    world.spawnParticle(Particle.ENCHANTMENT_TABLE,
            location, 30, 1, 1, 1, 0.1);
    world.spawnParticle(Particle.FIREWORKS_SPARK,
            location, 20, 1, 1, 1, 0.1);

    for (Player player : Bukkit.getOnlinePlayers()) {
        Lang.SPAWNED.send(player,
                new Pair("%id%", boss.getId()),
                new Pair("%name%", boss.getName())
        );
    }
}

private void broadcastBossStatus() {
    Server server = Bukkit.getServer();

    List<Map.Entry<String, Integer>> damageList = Handler.getSortedDamageList();
    for (int index = 0; index < damageList.size(); index++) {
        Map.Entry<String, Integer> entry = damageList.get(index);

        String playerName = entry.getKey();
        Player player = server.getPlayer(playerName);
        if (player == null) continue;

        int damage = entry.getValue();

        Component actionBar = Component.text(
                Configs.MAIN_CONFIG.getActionBar()
                        .replace("%index%", String.valueOf(index + 1))
                        .replace("%max%", String.valueOf(damageList.size()))
                        .replace("%damage%", String.valueOf(damage))
        );
        player.sendActionBar(actionBar);
    }
}

И на будущее - код вставлять лучше вот так:
Посмотреть вложение 66352
В качестве языка выбирай PHP, у него лучше всего подсветка. Получится так же, как под мои спойлером

У меня Purpur. Я сейчас попробую, кое-что сделать, может заработает.
 
Отдельное спасибо, за исправление кода.
 
Возможно проблема в моём ядре. Но я решил проблему другим путём, чтобы он проверял по UUID, а не Metadata и получал сущность через UUID. Спасибо, что решил подсказать как решить проблему, сказав проверить через UUID. Я просто совсем уже забыл про это.

Спасибо, что помог.

Тема закрыта.
 
Статус
Закрыто для дальнейших ответов.

Поделиться этой страницей

Назад
Верх