Помогите Интерфейс SkullMeta, метод setOwningPlayer/setOwner ведет себя не адекватно

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

MurlikMurlik

Активный участник
Пользователь
Баллы
96
Доброго времени суток.
Решил по изучать плагин TrophyHeads. Ранее мне было известно о том, что в таймингах этот плагин довольно часто виднеется.
Код:
TrophyHeads v1.12.7-21Total: 0.731 s    Pct: 0.12%
   Pct Total    Pct Tick       Total          Avg     PerTick         Count        Event
       0.10%     655.82%      0.66 s       327.91 ms     0.0           0.0k        TrophyHeads::onPlayerDeathEvent(PlayerDeathEvent)
       0.01%       0.03%      0.06 s         0.02 ms     0.3           3.6k        TrophyHeads::onEntityDeathEvent(EntityDeathEvent)
       0.00%       0.00%      0.02 s         0.00 ms     1.0          11.5k        TrophyHeads::onPlayerInteractEvent(PlayerInteractEvent)
       0.00%       0.00%      0.00 s         0.00 ms     0.3           3.7k        TrophyHeads::onBlockBreakEvent(BlockBreakEvent)
       0.00%       0.00%      0.00 s         0.00 ms     0.1           1.3k        TrophyHeads::onPrepareItemCraftEvent(PrepareItemCraftEvent)
Решил изучить эту проблему, и наткнулся на большие трудности.
Если игрок умирает, то есть, при попытке сдропать голову - сервер подвисает, то есть, коннектиться к моджангу. (Это с методом setOwner())
Имея исходники, решил заменить устаревший метод на новый (setOwningPlayer()).
Преобразуя Player в OfflinePlayer (OfflinePlayer ofpla = (OfflinePlayer) player), добавил мету в предмет, я почти добился результата.
Но как только дело доходит до метода дропа этой вещи, сервер зависает, опять подключаясь к моджангу.
Теперь вопросы.
Почему это так выходит и как теперь нормально можно делать головы со скинами? (трешово, когда например на сервере 500 человек, и каждую сек умирает по 10 новых игроков(которые никогда не заходили), подгружая инфу с моджанга)
Как с этой проблемой справились большие сервера? Ведь у большей части стоит ядро spigot/craftbukkit..

(Все еще являюсь новичком в Java.)
 
Подгружать в кеш головы игроков при заходе в асинхронном потоке. Заменять скин на кешированный.
 
Подгружать в кеш головы игроков при заходе в асинхронном потоке. Заменять скин на кешированный.
В этом и является основная проблема.
Как бы ты не подгружал голову, ядро все равно в основном потоке будет подключаться к моджангу.
Даже если известен ник и uuid..
 
Ведь у большей части стоит ядро spigot/craftbukkit.
В самых топовых - самопис или свой форк. Там кажись что-то фиксили несколько месяцев назад с головами, не уверен помогло ли оно.
 
В самых топовых - самопис или свой форк. Там кажись что-то фиксили несколько месяцев назад с головами, не уверен помогло ли оно.
Хотел бы уточнить, что именно и кто фиксил? Разработчики ядра или люди форков?
Просто я недавно собирал послдний билд, на сайте не находил ничего про головы
 
Есть ли какие нибудь варианты решения этой проблемы, не прибегая к модификации ядра?
 
Просто я недавно собирал послдний билд, на сайте не находил ничего про головы
Ну если на последнем, значит не помогло. Есть чувство что могли пофиксить на PaperSpigot, но что-то не уверен.
 
В папере это фиксили, там есть специальный метод для этого
 
В этом и является основная проблема.
Как бы ты не подгружал голову, ядро все равно в основном потоке будет подключаться к моджангу.
Даже если известен ник и uuid..
Нет не будет, я уже делал в асинхронном. Нужно немного головой думать и все збс.
 
В папере это фиксили, там есть специальный метод для этого
Если это правда, то стоит мне прямо сейчас переходить на этот форк?
Ведь я не понимаю, почему обычный spigot не пофиксили?
 
Нет не будет, я уже делал в асинхронном. Нужно немного головой думать и все збс.
Ну хорошо.
Что делал я:
Создал класс типа
Код:
public class SpawnThread extends Thread {
    private TrophyHeads plugin;
    private World w;
    private ItemStack item;
    private Location loc;
    public SpawnThread(TrophyHeads plugin, World w, ItemStack item, Location loc) {
        this.plugin = plugin;
        this.item = item;
        this.w = w;
        this.loc = loc;
        run();
    }
    @Override
    public void run() {
         w.dropItemNaturally(loc, item);
         plugin.getLogger().info("ТЕСТ!!!");
    }
}

А дальше, когда игрок умирает происходит следующее:
Код:
            Bukkit.getLogger().info("Я тут конвертирую игрока в офлайн игрока..");
            OfflinePlayer fpla = (OfflinePlayer) player;
            Bukkit.getLogger().info("Вроде конвертировал");
            ((SkullMeta) itemMeta).setOwningPlayer(fpla);
            Bukkit.getLogger().info("Установил мету");
            item.setItemMeta(itemMeta);
            Bukkit.getLogger().info("Дропаю вещь");
            Thread thread1 = new Thread(new SpawnThread(this, world, item, loc));
            thread1.start();
            Bukkit.getLogger().info("Все закончил.");

И все равно, на методе dropItemNaturally(loc, item) начинается фигня, подключается к моджангу в основном потоке, что наверное логично. Как бы сделал ты тогда?
 
Ну хорошо.
Что делал я:
Создал класс типа
Код:
public class SpawnThread extends Thread {
    private TrophyHeads plugin;
    private World w;
    private ItemStack item;
    private Location loc;
    public SpawnThread(TrophyHeads plugin, World w, ItemStack item, Location loc) {
        this.plugin = plugin;
        this.item = item;
        this.w = w;
        this.loc = loc;
        run();
    }
    @Override
    public void run() {
         w.dropItemNaturally(loc, item);
         plugin.getLogger().info("ТЕСТ!!!");
    }
}

А дальше, когда игрок умирает происходит следующее:
Код:
            Bukkit.getLogger().info("Я тут конвертирую игрока в офлайн игрока..");
            OfflinePlayer fpla = (OfflinePlayer) player;
            Bukkit.getLogger().info("Вроде конвертировал");
            ((SkullMeta) itemMeta).setOwningPlayer(fpla);
            Bukkit.getLogger().info("Установил мету");
            item.setItemMeta(itemMeta);
            Bukkit.getLogger().info("Дропаю вещь");
            Thread thread1 = new Thread(new SpawnThread(this, world, item, loc));
            thread1.start();
            Bukkit.getLogger().info("Все закончил.");

И все равно, на методе dropItemNaturally(loc, item) начинается фигня, подключается к моджангу в основном потоке, что наверное логично. Как бы сделал ты тогда?
Я не дропал в паралельном потоке, а копировал предмет через NMS. Посмотри что делает метод dropItemNaturally, там идет копирование предмета (головы), и как раз при копировании идет загрузка данных скина. После копирования скин идет в кеш. По сути я перед этим в асинхронном копировал, а потом уже дропал в обычном, получалось, что скин уже был в кеше и оно не брало по второму разу.
 
Я не дропал в паралельном потоке, а копировал предмет через NMS. Посмотри что делает метод dropItemNaturally, там идет копирование предмета (головы), и как раз при копировании идет загрузка данных скина. После копирования скин идет в кеш. По сути я перед этим в асинхронном копировал, а потом уже дропал в обычном, получалось, что скин уже был в кеше и оно не брало по второму разу.
Что то не работает твой вариант, мб я не так что сделал?
Код:
public class AsyncTest extends BukkitRunnable{
    private TrophyHeads plugin;
    private ItemStack item;
    public AsyncTest(TrophyHeads plugin, ItemStack item) {
        this.plugin = plugin;
        this.item = item;
        runnable();
    }
    @Override
    public void run() {
        plugin.getLogger().info("Тест1");
        CraftItemStack.asNMSCopy(item);
        plugin.getLogger().info("Тест2");
    }
    public void runnable() {
        ((AsyncTest)this).runTaskAsynchronously((Plugin)this.plugin);
    }

}

Код:
            Bukkit.getLogger().info("Я тут конвертирую игрока в офлайн игрока..");
            OfflinePlayer fpla = (OfflinePlayer) player;
            Bukkit.getLogger().info("Вроде конвертировал");
            ((SkullMeta) itemMeta).setOwningPlayer(fpla);
            Bukkit.getLogger().info("Установил мету");
            Bukkit.getLogger().info("Прикрепляю мету");
            item.setItemMeta(itemMeta);
            Bukkit.getLogger().info("Асинхронно добавляю вроде");
            new AsyncTest(this, item);
            Bukkit.getLogger().info("Дропаю вещь");
               world.dropItemNaturally(loc, item);
            Bukkit.getLogger().info("Все закончил.");

Все так же, при выпадении вещи, AutoSaveWorld оповещает меня о том, что этот плагин в основном потоке к моджангу коннектится, и сервер подвисает..
А сами методы которые асинхронном, выполняются вообще тогда, когда уже все основное выполнено..

Код:
[21:02:57] [Server thread/INFO]: Я тут конвертирую игрока в офлайн игрока..
[21:02:57] [Server thread/INFO]: Вроде конвертировал
[21:02:57] [Server thread/INFO]: Установил мету
[21:02:57] [Server thread/INFO]: Прикрепляю мету
[21:02:57] [Server thread/INFO]: Асинхронно добавляю вроде
[21:02:57] [Server thread/INFO]: Дропаю вещь
[21:02:57] [Server thread/WARN]: [AutoSaveWorld] Plugin TrophyHeads attempted to establish connection socket://api.mojang.com:443 in main server thread
[21:02:58] [Server thread/WARN]: [AutoSaveWorld] Plugin TrophyHeads attempted to establish connection socket://sessionserver.mojang.com:443 in main server thread
[21:02:58] [Server thread/INFO]: Все закончил.
[21:02:58] [Craft Scheduler Thread - 117/INFO]: [TrophyHeads] Тест1
[21:02:58] [Craft Scheduler Thread - 117/INFO]: [TrophyHeads] Тест2
 
Что то не работает твой вариант, мб я не так что сделал?
Код:
public class AsyncTest extends BukkitRunnable{
    private TrophyHeads plugin;
    private ItemStack item;
    public AsyncTest(TrophyHeads plugin, ItemStack item) {
        this.plugin = plugin;
        this.item = item;
        runnable();
    }
    @Override
    public void run() {
        plugin.getLogger().info("Тест1");
        CraftItemStack.asNMSCopy(item);
        plugin.getLogger().info("Тест2");
    }
    public void runnable() {
        ((AsyncTest)this).runTaskAsynchronously((Plugin)this.plugin);
    }

}

Код:
            Bukkit.getLogger().info("Я тут конвертирую игрока в офлайн игрока..");
            OfflinePlayer fpla = (OfflinePlayer) player;
            Bukkit.getLogger().info("Вроде конвертировал");
            ((SkullMeta) itemMeta).setOwningPlayer(fpla);
            Bukkit.getLogger().info("Установил мету");
            Bukkit.getLogger().info("Прикрепляю мету");
            item.setItemMeta(itemMeta);
            Bukkit.getLogger().info("Асинхронно добавляю вроде");
            new AsyncTest(this, item);
            Bukkit.getLogger().info("Дропаю вещь");
               world.dropItemNaturally(loc, item);
            Bukkit.getLogger().info("Все закончил.");

Все так же, при выпадении вещи, AutoSaveWorld оповещает меня о том, что этот плагин в основном потоке к моджангу коннектится, и сервер подвисает..
А сами методы которые асинхронном, выполняются вообще тогда, когда уже все основное выполнено..

Код:
[21:02:57] [Server thread/INFO]: Я тут конвертирую игрока в офлайн игрока..
[21:02:57] [Server thread/INFO]: Вроде конвертировал
[21:02:57] [Server thread/INFO]: Установил мету
[21:02:57] [Server thread/INFO]: Прикрепляю мету
[21:02:57] [Server thread/INFO]: Асинхронно добавляю вроде
[21:02:57] [Server thread/INFO]: Дропаю вещь
[21:02:57] [Server thread/WARN]: [AutoSaveWorld] Plugin TrophyHeads attempted to establish connection socket://api.mojang.com:443 in main server thread
[21:02:58] [Server thread/WARN]: [AutoSaveWorld] Plugin TrophyHeads attempted to establish connection socket://sessionserver.mojang.com:443 in main server thread
[21:02:58] [Server thread/INFO]: Все закончил.
[21:02:58] [Craft Scheduler Thread - 117/INFO]: [TrophyHeads] Тест1
[21:02:58] [Craft Scheduler Thread - 117/INFO]: [TrophyHeads] Тест2
Код:
new AsyncTest(this, item);
Bukkit.getLogger().info("Дропаю вещь");
Как видишь, ты сначала дропаешь вещь, а потом копируешь. Ты запустил AsyncTest, и сразу же после него продолжаешь дропать. А значит с большой вероятностью в основном потоке сначала скопируется предмет, а потом в твоем. Тебе нужно сделать через колбек или через CompletableFuture, чтобы ты выполнил дроп только после того, как закончится асинхронное выполнение.
Примерно так:
PHP:
CompletableFuture.runAsync(() -> {
    Bukkit.getLogger().info("Копирую вещь");
    CraftItemStack.asNMSCopy(item);
}).thenRun(() -> {
    Bukkit.getLogger().info("Дропаю вещь");
    world.dropItemNaturally(loc, item);
});
 
Ну и что? Соблюдать лимит и прогружать по готовности.
Пол минуты RATE LIMITED. Посмотрел бы я на такое при хотя бы 100 онлайне. Без кеширования скин профиля не обойтись.
 
Последнее редактирование:
Пол минуты RATE LIMITED. Посмотрел бы я на такое при хотя бы 100 онлайне. Без кеширования скин профиля не обойтись.
Я же писал:
Подгружать в кеш головы игроков при заходе в асинхронном потоке. Заменять скин на кешированный.
Надолго то есть кешировать.
 
Статус
Закрыто для дальнейших ответов.
Назад
Верх