Помогите Интерфейс 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.)
 
Код:
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);
});
Вроде работает, только дропа нет после смерти почему то.
По сообщениям видно что вроде поток другой совсем.
Но после смерти, вещи не было, хотя я установил 100% шанс выпадения. Исключений тоже нет..
Код:
[15:22:49] [Server thread/INFO]: Я тут конвертирую игрока в офлайн игрока..
[15:22:49] [Server thread/INFO]: Вроде конвертировал
[15:22:49] [Server thread/INFO]: Установил мету
[15:22:49] [Server thread/INFO]: Прикрепляю мету
[15:22:49] [Server thread/INFO]: Все закончил.
[15:22:49] [ForkJoinPool.commonPool-worker-2/INFO]: Копирую вещь
[15:22:49] [ForkJoinPool.commonPool-worker-2/INFO]: Дропаю вещь

UPD:
Написал более подробный дебаг.
Выходит так, что на методе world.dropItemNaturally(loc, item); "спотыкается" и все.
Ибо дальше я не вижу никаких дебажных сообщений.
Код:
[16:02:48] [Server thread/INFO]: Я тут конвертирую игрока в офлайн игрока..
[16:02:48] [Server thread/INFO]: Вроде конвертировал
[16:02:48] [Server thread/INFO]: Установил мету
[16:02:48] [Server thread/INFO]: Прикрепляю мету
[16:02:48] [ForkJoinPool.commonPool-worker-0/INFO]: Копирую вещь SKULL_ITEM
[16:02:48] [ForkJoinPool.commonPool-worker-0/INFO]: Вроде скопировал..
[16:02:48] [ForkJoinPool.commonPool-worker-0/INFO]: Дропаю вещь SKULL_ITEM
[16:02:48] [Server thread/INFO]: Все закончил здесь.
 
Последнее редактирование:
Вроде работает, только дропа нет после смерти почему то.
По сообщениям видно что вроде поток другой совсем.
Но после смерти, вещи не было, хотя я установил 100% шанс выпадения. Исключений тоже нет..
Код:
[15:22:49] [Server thread/INFO]: Я тут конвертирую игрока в офлайн игрока..
[15:22:49] [Server thread/INFO]: Вроде конвертировал
[15:22:49] [Server thread/INFO]: Установил мету
[15:22:49] [Server thread/INFO]: Прикрепляю мету
[15:22:49] [Server thread/INFO]: Все закончил.
[15:22:49] [ForkJoinPool.commonPool-worker-2/INFO]: Копирую вещь
[15:22:49] [ForkJoinPool.commonPool-worker-2/INFO]: Дропаю вещь
А попробуй запихнуть дроп в баккит таск, оно должно то в главном потоке дропать.
 
А попробуй запихнуть дроп в баккит таск, оно должно то в главном потоке дропать.
Вроде так же баккитом сделал асинхронном, как делал выше, но ругается все равно.
Код:
[16:10:50] [Craft Scheduler Thread - 25/INFO]: [TrophyHeads] Тест1
[16:10:50] [Craft Scheduler Thread - 25/WARN]: [TrophyHeads] Plugin TrophyHeads v2.1.2 generated an exception while executing task 8805
java.lang.IllegalStateException: Asynchronous entity add!
    at org.spigotmc.AsyncCatcher.catchOp(AsyncCatcher.java:14) ~[spigot-1.12.2.jar:git-Spigot-642f6d2-6103339]
    at net.minecraft.server.v1_12_R1.World.addEntity(World.java:1017) ~[spigot-1.12.2.jar:git-Spigot-642f6d2-6103339]
    at net.minecraft.server.v1_12_R1.WorldServer.addEntity(WorldServer.java:1115) ~[spigot-1.12.2.jar:git-Spigot-642f6d2-6103339]
    at org.bukkit.craftbukkit.v1_12_R1.CraftWorld.dropItem(CraftWorld.java:295) ~[spigot-1.12.2.jar:git-Spigot-642f6d2-6103339]
    at org.bukkit.craftbukkit.v1_12_R1.CraftWorld.dropItemNaturally(CraftWorld.java:334) ~[spigot-1.12.2.jar:git-Spigot-642f6d2-6103339]
    at ru.BoomEaro.TrophyHeads.AsyncTest.run(AsyncTest.java:31) ~[?:?]
    at org.bukkit.craftbukkit.v1_12_R1.scheduler.CraftTask.run(CraftTask.java:76) ~[spigot-1.12.2.jar:git-Spigot-642f6d2-6103339]
    at org.bukkit.craftbukkit.v1_12_R1.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:52) [spigot-1.12.2.jar:git-Spigot-642f6d2-6103339]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [?:1.8.0_121]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [?:1.8.0_121]
    at java.lang.Thread.run(Unknown Source) [?:1.8.0_121]
 
Вроде так же баккитом сделал асинхронном, как делал выше, но ругается все равно.
Код:
[16:10:50] [Craft Scheduler Thread - 25/INFO]: [TrophyHeads] Тест1
[16:10:50] [Craft Scheduler Thread - 25/WARN]: [TrophyHeads] Plugin TrophyHeads v2.1.2 generated an exception while executing task 8805
java.lang.IllegalStateException: Asynchronous entity add!
    at org.spigotmc.AsyncCatcher.catchOp(AsyncCatcher.java:14) ~[spigot-1.12.2.jar:git-Spigot-642f6d2-6103339]
    at net.minecraft.server.v1_12_R1.World.addEntity(World.java:1017) ~[spigot-1.12.2.jar:git-Spigot-642f6d2-6103339]
    at net.minecraft.server.v1_12_R1.WorldServer.addEntity(WorldServer.java:1115) ~[spigot-1.12.2.jar:git-Spigot-642f6d2-6103339]
    at org.bukkit.craftbukkit.v1_12_R1.CraftWorld.dropItem(CraftWorld.java:295) ~[spigot-1.12.2.jar:git-Spigot-642f6d2-6103339]
    at org.bukkit.craftbukkit.v1_12_R1.CraftWorld.dropItemNaturally(CraftWorld.java:334) ~[spigot-1.12.2.jar:git-Spigot-642f6d2-6103339]
    at ru.BoomEaro.TrophyHeads.AsyncTest.run(AsyncTest.java:31) ~[?:?]
    at org.bukkit.craftbukkit.v1_12_R1.scheduler.CraftTask.run(CraftTask.java:76) ~[spigot-1.12.2.jar:git-Spigot-642f6d2-6103339]
    at org.bukkit.craftbukkit.v1_12_R1.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:52) [spigot-1.12.2.jar:git-Spigot-642f6d2-6103339]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [?:1.8.0_121]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [?:1.8.0_121]
    at java.lang.Thread.run(Unknown Source) [?:1.8.0_121]
runTaskLater юзай.
 
Вроде так же баккитом сделал асинхронном, как делал выше, но ругается все равно.
Код:
[16:10:50] [Craft Scheduler Thread - 25/INFO]: [TrophyHeads] Тест1
[16:10:50] [Craft Scheduler Thread - 25/WARN]: [TrophyHeads] Plugin TrophyHeads v2.1.2 generated an exception while executing task 8805
java.lang.IllegalStateException: Asynchronous entity add!
    at org.spigotmc.AsyncCatcher.catchOp(AsyncCatcher.java:14) ~[spigot-1.12.2.jar:git-Spigot-642f6d2-6103339]
    at net.minecraft.server.v1_12_R1.World.addEntity(World.java:1017) ~[spigot-1.12.2.jar:git-Spigot-642f6d2-6103339]
    at net.minecraft.server.v1_12_R1.WorldServer.addEntity(WorldServer.java:1115) ~[spigot-1.12.2.jar:git-Spigot-642f6d2-6103339]
    at org.bukkit.craftbukkit.v1_12_R1.CraftWorld.dropItem(CraftWorld.java:295) ~[spigot-1.12.2.jar:git-Spigot-642f6d2-6103339]
    at org.bukkit.craftbukkit.v1_12_R1.CraftWorld.dropItemNaturally(CraftWorld.java:334) ~[spigot-1.12.2.jar:git-Spigot-642f6d2-6103339]
    at ru.BoomEaro.TrophyHeads.AsyncTest.run(AsyncTest.java:31) ~[?:?]
    at org.bukkit.craftbukkit.v1_12_R1.scheduler.CraftTask.run(CraftTask.java:76) ~[spigot-1.12.2.jar:git-Spigot-642f6d2-6103339]
    at org.bukkit.craftbukkit.v1_12_R1.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:52) [spigot-1.12.2.jar:git-Spigot-642f6d2-6103339]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [?:1.8.0_121]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [?:1.8.0_121]
    at java.lang.Thread.run(Unknown Source) [?:1.8.0_121]
Дак не асинхронном, говорю же в основном должно быть, просто runTask
 
PHP:
CompletableFuture.runAsync(() -> {
    Bukkit.getLogger().info("Копирую вещь");
    CraftItemStack.asNMSCopy(item);
}).thenRun(() -> {
    Bukkit.getScheduler().runTask(plugin, () -> {
        Bukkit.getLogger().info("Дропаю вещь");
        world.dropItemNaturally(loc, item);
    });
});
 
PHP:
CompletableFuture.runAsync(() -> {
    Bukkit.getLogger().info("Копирую вещь");
    CraftItemStack.asNMSCopy(item);
}).thenRun(() -> {
    Bukkit.getScheduler().runTask(plugin, () -> {
        Bukkit.getLogger().info("Дропаю вещь");
        world.dropItemNaturally(loc, item);
    });
});
Почти каждое убийство теперь выглядит так в тайминге:
Код:
       0.25%      28.21%      0.01 s        14.11 ms     0.0           0.0k        TrophyHeads::onPlayerDeathEvent(PlayerDeathEvent)
       0.12%      13.67%      0.01 s         6.84 ms     0.0           0.0k        Task: TrophyHeads$$Lambda$132/605064028(Single)
А когда игрок не был на сервере по крайней мере после перезагрузки, оно светится красным и процент в 2 раза больше.
По сути.. ничего не изменилось выходит..
 
Почти каждое убийство теперь выглядит так в тайминге:
Код:
       0.25%      28.21%      0.01 s        14.11 ms     0.0           0.0k        TrophyHeads::onPlayerDeathEvent(PlayerDeathEvent)
       0.12%      13.67%      0.01 s         6.84 ms     0.0           0.0k        Task: TrophyHeads$$Lambda$132/605064028(Single)
А когда игрок не был на сервере по крайней мере после перезагрузки, оно светится красным и процент в 2 раза больше.
По сути.. ничего не изменилось выходит..
Интересно, я вот блин не припомню, какой конкретно из тех методов вызывал подключение к моджангу, но когда делал фикс одному челу, я делал через два метода, возможно это второй, что то не найду сейчас, попробуй еще так:
PHP:
CompletableFuture.runAsync(() -> {
    Bukkit.getLogger().info("Копирую вещь");
    CraftItemStack.asBukkitCopy(CraftItemStack.asNMSCopy(item));
}).thenRun(() -> {
    Bukkit.getScheduler().runTask(plugin, () -> {
        Bukkit.getLogger().info("Дропаю вещь");
        world.dropItemNaturally(loc, item);
    });
});

Было бы неплохо при себе иметь MassiveLag и видеть конкретные строчки, где залагивает. Может быть у тебя вообще не кеширует скины. Тогда нужно переопределять как то метод дропа предмета, и добавлять туда асинхрон на копирование.
 
Интересно, я вот блин не припомню, какой конкретно из тех методов вызывал подключение к моджангу, но когда делал фикс одному челу, я делал через два метода, возможно это второй, что то не найду сейчас, попробуй еще так:
PHP:
CompletableFuture.runAsync(() -> {
    Bukkit.getLogger().info("Копирую вещь");
    CraftItemStack.asBukkitCopy(CraftItemStack.asNMSCopy(item));
}).thenRun(() -> {
    Bukkit.getScheduler().runTask(plugin, () -> {
        Bukkit.getLogger().info("Дропаю вещь");
        world.dropItemNaturally(loc, item);
    });
});

Было бы неплохо при себе иметь MassiveLag и видеть конкретные строчки, где залагивает. Может быть у тебя вообще не кеширует скины. Тогда нужно переопределять как то метод дропа предмета, и добавлять туда асинхрон на копирование.
Там это выглядит так. Мб что то не так мы делаем?
Код:
    public org.bukkit.entity.Item dropItem(Location loc, ItemStack item) {
        Validate.notNull(item, "Cannot drop a Null item.");
        EntityItem entity = new EntityItem(world, loc.getX(), loc.getY(), loc.getZ(), CraftItemStack.asNMSCopy(item));
        entity.pickupDelay = 10;
        world.addEntity(entity, SpawnReason.CUSTOM);
        // TODO this is inconsistent with how Entity.getBukkitEntity() works.
        // However, this entity is not at the moment backed by a server entity class so it may be left.
        return new CraftItem(world.getServer(), entity);
    }
 
Вообщем, ни один вариант не сработал к сожалению.
В таймингах все равно виднеется плагин, эти подвисания чувствуются даже без них.
Может быть есть еще варианты?
 
Вообщем, ни один вариант не сработал к сожалению.
В таймингах все равно виднеется плагин, эти подвисания чувствуются даже без них.
Может быть есть еще варианты?
Скопируй метод дропа из сурсов и сделай копирование предмета в асинхроне с CompletableFuture
 
Скопируй метод дропа из сурсов и сделай копирование предмета в асинхроне с CompletableFuture
Не получается привести к типу мир с апи в мир ванильного ядра (вроде)
Caused by: java.lang.ClassCastException: org.bukkit.craftbukkit.v1_12_R1.CraftWorld cannot be cast to net.minecraft.server.v1_12_R1.World
А так, я в принципе подумал, что реально твой способ с использованием своих методов на добавление предмета в мир, сможет помочь, и даже смогу замерить какой метод тормозит и подключается.
А пока, я нигде не нашел как можно конвертировать..

upd:
Код:
            new DropMethods(this).dropItemNaturally(loc, item, (net.minecraft.server.v1_12_R1.World) world);

Код:
public class DropMethods {
    private TrophyHeads plugin;
    
    public DropMethods(TrophyHeads plugin) {
        this.plugin = plugin;
    }
    
    
    public org.bukkit.entity.Item dropItemMy(Location loc, ItemStack item, net.minecraft.server.v1_12_R1.World world) {
        long time1 = System.currentTimeMillis();
        Validate.notNull(item, "Cannot drop a Null item.");
        EntityItem entity = new EntityItem(world, loc.getX(), loc.getY(), loc.getZ(), CraftItemStack.asNMSCopy(item));
        entity.pickupDelay = 10;
        world.addEntity(entity, SpawnReason.CUSTOM);
        long time2 = System.currentTimeMillis();
        long times = time2 - time1;
        plugin.getLogger().info("Потребовалось " + times + "ms");
        return new CraftItem(world.getServer(), entity);
    }
    
    public org.bukkit.entity.Item dropItemNaturally(Location loc, ItemStack item, net.minecraft.server.v1_12_R1.World world) {
        double xs = world.random.nextFloat() * 0.7F - 0.35D;
        double ys = world.random.nextFloat() * 0.7F - 0.35D;
        double zs = world.random.nextFloat() * 0.7F - 0.35D;
        loc = loc.clone();
        // Makes sure the new item is created within the block the location points to.
        // This prevents item spill in 1-block wide farms.
        randomLocationWithinBlock(loc, xs, ys, zs);
        return dropItemMy(loc, item, world);
    }
    
    private static void randomLocationWithinBlock(Location loc, double xs, double ys, double zs) {
        double prevX = loc.getX();
        double prevY = loc.getY();
        double prevZ = loc.getZ();
        loc.add(xs, ys, zs);
        if (loc.getX() < Math.floor(prevX)) {
            loc.setX(Math.floor(prevX));
        }
        if (loc.getX() >= Math.ceil(prevX)) {
            loc.setX(Math.ceil(prevX - 0.01));
        }
        if (loc.getY() < Math.floor(prevY)) {
            loc.setY(Math.floor(prevY));
        }
        if (loc.getY() >= Math.ceil(prevY)) {
            loc.setY(Math.ceil(prevY - 0.01));
        }
        if (loc.getZ() < Math.floor(prevZ)) {
            loc.setZ(Math.floor(prevZ));
        }
        if (loc.getZ() >= Math.ceil(prevZ)) {
            loc.setZ(Math.ceil(prevZ - 0.01));
        }
    }
}
 
Код:
    public static ItemStack setSkullSkin(ItemStack item, String name) {
        NBTTagCompound tag = new NBTTagCompound();
        try {
            String uuid = getUUID(name);
            try {
                //Тут некое получение SkinProfile из кеш базы.
                tag = MojangsonParser.parse(nbt(getSkinProfile(uuid)));
            } catch (MojangsonParseException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        NBTTagCompound nbt = new NBTTagCompound();
        CraftItemStack.asNMSCopy(item).save(nbt);
        nbt.set("tag", tag);
        return CraftItemStack.asBukkitCopy(new net.minecraft.server.v1_12_R1.ItemStack(nbt));
    }
 
Спасибо за код!
Вроде работает правильно, игроков кеширует, правда есть несколько вопросов.
Почему выполняется сразу 2 запроса?
Код:
[12:47:47] [Server thread/WARN]: [AutoSaveWorld] Plugin TrophyHeads attempted to establish connection https://api.mojang.com/profiles/minecraft in main server thread
[12:47:47] [Server thread/WARN]: [AutoSaveWorld] Plugin TrophyHeads attempted to establish connection socket://api.mojang.com:443 in main server thread
[12:47:47] [Server thread/WARN]: [AutoSaveWorld] Plugin TrophyHeads attempted to establish connection https://sessionserver.mojang.com/session/minecraft/profile/4a6525ce83b34640844488796f9a669f?unsigned=true in main server thread
[12:47:47] [Server thread/WARN]: [AutoSaveWorld] Plugin TrophyHeads attempted to establish connection socket://sessionserver.mojang.com:443 in main server thread
Ладно, я второй запрос в асинхрон пихну, но как быть с первым? Он вызывается именно на методе NBTCreator.setSkullSkin(item, pName);
Я не совсем понимаю, что там делают ивент на ломание блоков и ивент на крафты? Они же вроде не работают, да даже если бы работали, для чего они? (мне не ясна немного логика кода)
 
[12:47:47] [Server thread/WARN]: [AutoSaveWorld] Plugin TrophyHeads attempted to establish connection https://api.mojang.com/profiles/minecraft in main server thread
[12:47:47] [Server thread/WARN]: [AutoSaveWorld] Plugin TrophyHeads attempted to establish connection socket://api.mojang.com:443 in main server thread
Получение UUID.

[12:47:47] [Server thread/WARN]: [AutoSaveWorld] Plugin TrophyHeads attempted to establish connection https://sessionserver.mojang.com/se...a6525ce83b34640844488796f9a669f?unsigned=true in main server thread
[12:47:47] [Server thread/WARN]: [AutoSaveWorld] Plugin TrophyHeads attempted to establish connection socket://sessionserver.mojang.com:443 in main server thread

Получение скина.
 
Спасибо за код!
Вроде работает правильно, игроков кеширует, правда есть несколько вопросов.
Почему выполняется сразу 2 запроса?
Код:
[12:47:47] [Server thread/WARN]: [AutoSaveWorld] Plugin TrophyHeads attempted to establish connection https://api.mojang.com/profiles/minecraft in main server thread
[12:47:47] [Server thread/WARN]: [AutoSaveWorld] Plugin TrophyHeads attempted to establish connection socket://api.mojang.com:443 in main server thread
[12:47:47] [Server thread/WARN]: [AutoSaveWorld] Plugin TrophyHeads attempted to establish connection https://sessionserver.mojang.com/session/minecraft/profile/4a6525ce83b34640844488796f9a669f?unsigned=true in main server thread
[12:47:47] [Server thread/WARN]: [AutoSaveWorld] Plugin TrophyHeads attempted to establish connection socket://sessionserver.mojang.com:443 in main server thread
Ладно, я второй запрос в асинхрон пихну, но как быть с первым? Он вызывается именно на методе NBTCreator.setSkullSkin(item, pName);
Я не совсем понимаю, что там делают ивент на ломание блоков и ивент на крафты? Они же вроде не работают, да даже если бы работали, для чего они? (мне не ясна немного логика кода)
Первый запрос не имеет лимита, только второй getSkinProfile.
И да там есть прочие nms методы не связанные с головами. getPosition получает локацию где открыли верстак и последний получает звук ломания блоков.
 
Последнее редактирование:
Первый запрос не имеет лимита, только второй getSkinProfile.
И да там есть прочие nms методы не связанные с головами. getPosition получает локацию где открыли верстак и последний получает звук ломания блоков.
В таком случае, все отлично работает! Я в другом потоке выполнил метод установки головы, а потом там запустил задачу которая выполнит метод спавна лута.
В итоге, да, лаги прекратились, проблем по сути теперь нет, но осталась одна.
Если нет данных о игроке, то есть, игрок не имеет скин/лицензии, то один метод возвращает нулл, из-за чего другой метод вызывает исключение когда пытается реплейснуть строку.. Что делать с такими игроками?
 
В таком случае, все отлично работает! Я в другом потоке выполнил метод установки головы, а потом там запустил задачу которая выполнит метод спавна лута.
В итоге, да, лаги прекратились, проблем по сути теперь нет, но осталась одна.
Если нет данных о игроке, то есть, игрок не имеет скин/лицензии, то один метод возвращает нулл, из-за чего другой метод вызывает исключение когда пытается реплейснуть строку.. Что делать с такими игроками?
При null пропускай и юзай простую голову.
 
Статус
Закрыто для дальнейших ответов.
Назад
Верх