Определение количества блоков над игроком

Версия Minecraft
1.12.2
Добавил новый атрибут для игрока. Для постоянного его изменения (по аналогии с стандартным игровым голодом) мне понадобилось добавить переменную (float) radModifier, которая по умолчанию равна 1.0F, и которая должна уменьшаться на 30% с каждым найденным над игроком блоком (проще говоря, мне надо узнать количество плотных блоков над игроком) Для этого я воспользовался циклом "for". Но при наличии этого цикла в коде игра просто виснет, когда я пытаюсь войти в любой мир, а консоль говорит, что я пытаюсь выполнить слишком много операций за короткий промежуток времени. Есть ли какая-нибудь альтернатива моему способу (которая не будет заставлять игру виснуть)? Код ивента, логи и скрин ниже (Краш игры не происходит, клиент приходится закрывать насильно)screenshot.png).
Java:
@SubscribeEvent
    public static void onPlayerUpdate(LivingEvent.LivingUpdateEvent event) {

        float radModifier = 1.0F;

        if (event.getEntityLiving() instanceof EntityPlayer) {

            EntityPlayer player = (EntityPlayer) event.getEntityLiving();
            BlockPos pos = new BlockPos(player);
            boolean isSafe = false;

            if (player.ticksExisted % 60 == 0 && player.dimension == 0 && !player.capabilities.isCreativeMode) {

                for (int i = 1; i < 9; i++) {
                    BlockPos posF = pos.up(i);
                    if (player.world.getBlockState(posF) != Blocks.AIR) {

                        radModifier = radModifier - (radModifier / 100 * 30);
                        isSafe = true;
                        i = 1;

                    }
                    if (i == 8) {
                        if (!isSafe) {
                            radModifier = 1.0F;
                        }
                        break;
                    }

                }

                if (getRad(player) != 0 && getRad(player) != 199) {
                    increaseRad(player, radModifier - 0.3F);
                    saveRadToNBT(player);
                }
            }
        }

    }
[12:19:34] [Server thread/INFO] [minecraft/MinecraftServer]: Player734 joined the game
[12:19:39] [pool-2-thread-1/WARN] [mojang/YggdrasilMinecraftSessionService]: Couldn't look up profile properties for com.mojang.authlib.GameProfile@6eb42e56[id=3f66a67c-db6c-36b7-b762-d7a40c17883b,name=Player734,properties={},legacy=false]
com.mojang.authlib.exceptions.AuthenticationException: The client has sent too many requests within a certain amount of time
at com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService.makeRequest(YggdrasilAuthenticationService.java:79) ~[YggdrasilAuthenticationService.class:?]
at com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService.fillGameProfile(YggdrasilMinecraftSessionService.java:180) [YggdrasilMinecraftSessionService.class:?]
at com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService$1.load(YggdrasilMinecraftSessionService.java:60) [YggdrasilMinecraftSessionService$1.class:?]
at com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService$1.load(YggdrasilMinecraftSessionService.java:57) [YggdrasilMinecraftSessionService$1.class:?]
at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3716) [guava-21.0.jar:?]
at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2424) [guava-21.0.jar:?]
at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2298) [guava-21.0.jar:?]
at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2211) [guava-21.0.jar:?]
at com.google.common.cache.LocalCache.get(LocalCache.java:4154) [guava-21.0.jar:?]
at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:4158) [guava-21.0.jar:?]
at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:5147) [guava-21.0.jar:?]
at com.google.common.cache.LocalCache$LocalLoadingCache.getUnchecked(LocalCache.java:5153) [guava-21.0.jar:?]
at com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService.fillProfileProperties(YggdrasilMinecraftSessionService.java:170) [YggdrasilMinecraftSessionService.class:?]
at net.minecraft.client.Minecraft.getProfileProperties(Minecraft.java:3181) [Minecraft.class:?]
at net.minecraft.client.resources.SkinManager$3.run(SkinManager.java:138) [SkinManager$3.class:?]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_181]
at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) [?:1.8.0_181]
at java.util.concurrent.FutureTask.run(FutureTask.java) [?:1.8.0_181]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_181]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_181]
at java.lang.Thread.run(Thread.java:748) [?:1.8.0_181]
 
Решение
Java:
@Mod.EventBusSubscriber(modid = MainClass.MODID)
public class RadiationHandler {

    private static Thread kek = null;
    
    public static float getRadMax(EntityPlayer player) {

        return (float) player.getEntityAttribute(PropRegistry.RAD_MAX).getAttributeValue();

    }

    public static float getRad(EntityPlayer player) {

        return player.getDataManager().get(PropRegistry.RAD);

    }

    public static void increaseRad(EntityPlayer player, float value) {

        player.getDataManager().set(PropRegistry.RAD, MathHelper.clamp(getRad(player) - value, 0.0F, getRadMax(player)));
    }

    public static void setRad(EntityPlayer player, float value) {

        player.getDataManager().set(PropRegistry.RAD...
Цикл не останавливается и причина этого в цикле есть "i = 1;"
По задумке i должно быть равно 1 только тогда, когда игра находит 1 блок над игроком и это нужно, чтобы она чекала каждый блок до тех пор, пока не дойдет до открытого пространства высотой 7 блоков воздуха. Если она находит такое пространство, то уменьшение параметра radModifier останавливается, и в этот момент игра должна взять этот параметр и применить. Если не делать сброс переменной i, то игра чекнет 7 блоков над игроком и в любом случае остановится, а тогда не будут учитываться блоки над этой зоной, что есть плохо.
 
68
1
7
68
1
7
Если данные из класса не берёшь, то это всё можно вынести в отдельный поток и всё наверно. Но, если ты оставишь создание потока в слушателе, то сам поток создай в классе, слушателе сначала проверь, запущен ли он, если нет, то запусти
 
68
1
7
Т.к. поток можно запустить только один раз. Создай внутренний класс

Java:
private static class Kek extends Thread{
    @Override
    public void run(){
        //всё то что было в методе со слушателем
    }
}

В класс добавь поле Thread kek = null;

В методе

Java:
if(kek == null || kek.getState()==State.TERMINATED ){
    kek = new Kek();
    kek.start();
}
 
Последнее редактирование:
68
1
7
А если данные из класса применяются в других?
Вот про эти сложности я и говорил. Тут уже костыли пойдут скорее всего. Примитивные типы, на примере int переделать в
final int[] i = new int[1]; Объекты тоже в final и надеяться что они не immutable
 
А какие данные используются этим методом и другими классами?

getRad() берется и, после обработки, передается в другой класс для реализации рендера индикатора, если речь об этом. Также берутся некоторые методы из этого же самого класса (например saveRadToNBT)
 
68
1
7
getRad() берется и, после обработки, передается в другой класс для реализации рендера индикатора, если речь об этом. Также берутся некоторые методы из этого же самого класса (например saveRadToNBT)
Методы вообще не роляют. Главное то, что в методе onPlayerUpdate, т.к. его можно попробовать вынести в отдельный поток
 
А можно код всего класса увидеть?
Вот код класса:
Java:
@Mod.EventBusSubscriber(modid = MainClass.MODID)
public class RadiationHandler {

    public static float getRadMax(EntityPlayer player) {

        return (float) player.getEntityAttribute(PropRegistry.RAD_MAX).getAttributeValue();

    }

    public static float getRad(EntityPlayer player) {

        return player.getDataManager().get(PropRegistry.RAD);

    }

    public static void increaseRad(EntityPlayer player, float value) {

        player.getDataManager().set(PropRegistry.RAD, MathHelper.clamp(getRad(player) - value, 0.0F, getRadMax(player)));
    }

    public static void setRad(EntityPlayer player, float value) {

        player.getDataManager().set(PropRegistry.RAD, MathHelper.clamp(value, 0.0F, getRadMax(player)));
    }

    private static void saveRadToNBT(EntityPlayer player) {

        player.getEntityData().setFloat(MainClass.MODID + ":rad", getRad(player));
    }

    private static float loadRadFromNBT(EntityPlayer player) {

        return player.getEntityData().hasKey(MainClass.MODID + ":rad") ?
                player.getEntityData().getFloat(MainClass.MODID + ":rad") : getRadMax(player);
    }

    @SubscribeEvent
    public static void onPlayerLogIn(PlayerEvent.PlayerLoggedInEvent event) {

        setRad(event.player, loadRadFromNBT(event.player));
    }

    @SideOnly(Side.SERVER)
    @SubscribeEvent
    public static void onPlayerLogOut(PlayerEvent.PlayerLoggedOutEvent event) {

        saveRadToNBT(event.player);
    }

    @SubscribeEvent
    public static void onPlayerUpdate(LivingEvent.LivingUpdateEvent event) {

        float radModifier = 1.0F;

        if (event.getEntityLiving() instanceof EntityPlayer) {

            EntityPlayer player = (EntityPlayer) event.getEntityLiving();
            BlockPos pos = new BlockPos(player);
            boolean isSafe = false;

            if (player.ticksExisted % 60 == 0 && player.dimension == 0 && !player.capabilities.isCreativeMode) {

                for (int i = 1; i < 9; i++) {
                    BlockPos posF = pos.up(i);
                    if (player.world.getBlockState(posF) != Blocks.AIR) {

                        radModifier = radModifier - (radModifier / 100 * 30);
                        isSafe = true;
                        i = 1;

                    }
                    if (i == 8) {
                        if (!isSafe) {
                            radModifier = 1.0F;
                        }
                        break;
                    }

                }

                if (getRad(player) != 0 && getRad(player) != 199) {
                    increaseRad(player, radModifier - 0.3F);
                    saveRadToNBT(player);
                }
            }
        }

    }

}
 
Сверху