Хостинг серверов Minecraft playvds.com
  1. Вы находитесь в русском сообществе Bukkit. Мы - администраторы серверов Minecraft, разрабатываем собственные плагины и переводим на русский язык плагины наших собратьев из других стран.
    Скрыть объявление

Помогите Лучший вариант getNearbyEntities

Тема в разделе "Разработка плагинов для новичков", создана пользователем Exception_Prototype, 26 фев 2017.

  1. Автор темы
    Exception_Prototype

    Exception_Prototype Активный участник Пользователь

    Баллы:
    46
    Всё таки и я задался вопросов о максимально лучшем варианте получения живности вокруг в указанном радиусе.
    Нашёл код ниже здесь. Хотелось бы узнать мнение знающих людей, а частности очень интересует мнение @AtomicInteger, ибо он очень часто упоминал о доработке стандартного getNearbyEntities().
    Код:
        public static List<Entity> getEntitiesAroundPoint(Location location, double radius) {
            List<Entity> entities = new ArrayList<>();
            World world = location.getWorld();
    
            // To find chunks we use chunk coordinates (not block coordinates!)
            int smallX = MathHelper.floor((location.getX() - radius) / 16.0D);
            int bigX = MathHelper.floor((location.getX() + radius) / 16.0D);
            int smallZ = MathHelper.floor((location.getZ() - radius) / 16.0D);
            int bigZ = MathHelper.floor((location.getZ() + radius) / 16.0D);
    
            for (int x = smallX; x <= bigX; x++) {
                for (int z = smallZ; z <= bigZ; z++) {
                    if (world.isChunkLoaded(x, z)) {
                        entities.addAll(Arrays.asList(world.getChunkAt(x, z).getEntities())); // Add all entities from this chunk to the list
                    }
                }
            }
    
            // Remove the entities that are within the box above but not actually in the sphere we defined with the radius and location
            // This code below could probably be replaced in Java 8 with a stream -> filter
            Iterator<Entity> entityIterator = entities.iterator(); // Create an iterator so we can loop through the list while removing entries
            while (entityIterator.hasNext()) {
                if (entityIterator.next().getLocation().distanceSquared(location) > radius * radius) { // If the entity is outside of the sphere...
                    entityIterator.remove(); // Remove it
                }
            }
            return entities;
        }
    
    Единственно IDE ругается на MathHelper.floor, чё это такое?
    А всё, нашёл https://github.com/Bukkit/mc-dev/blob/master/net/minecraft/server/MathHelper.java
     
    Последнее редактирование: 26 фев 2017
  2. Хостинг MineCraft
    <
  3. Blc_Dragon

    Blc_Dragon Активный участник Пользователь

    Баллы:
    76
    Имя в Minecraft:
    Blc_Dragon
    вообще в яве есть Math.floor - округление до ближайшего наименьшего целого числа.
    класс MathHelper вообще первый раз вижу
     
  4. Автор темы
    Exception_Prototype

    Exception_Prototype Активный участник Пользователь

    Баллы:
    46
    https://github.com/Bukkit/mc-dev/blob/master/net/minecraft/server/MathHelper.java[DOUBLEPOST=1488108379,1488105726][/DOUBLEPOST]Собственно провёл тесты:
    "Родной" метод быстрей метода выше при маленьких радиуса на 1-2 секунды.
    Но когда радиус был установлен типа 300000, то метод выше оказался быстрей на секунду.
    Крч я хз.
     
  5. alexandrage

    alexandrage Администратор

    Баллы:
    173
    Skype:
    alexandr0116
    Конечно быстрее, ибо он кубический.[DOUBLEPOST=1488129902][/DOUBLEPOST]P.s могу поделится своим извращением, рисовал от нефиг делать. :D

    Код:
        Collection<Entity> test(Player p) {
            Location loc = p.getLocation().add(0,1.5,0);
            Collection<Entity> nearbyEntites = new ArrayList<Entity>();
            for(int i = 0;i<5; i++) {
                Vector durect = loc.getDirection().multiply(i);
                loc.add(durect);
                nearbyEntites.addAll(loc.getWorld().getNearbyEntities(loc, 1, 1, 1));
                nearbyEntites.remove(p);
                Iterator<Entity> it = nearbyEntites.iterator();
                while(it.hasNext()) {
                    if(!(it.next() instanceof LivingEntity)) {
                        it.remove();
                    }
                }
                if(nearbyEntites.size()!=0) {
                    break;
                }
            }
            return nearbyEntites;
        }
     
  6. AtomicInteger

    AtomicInteger Активный участник Пользователь

    Баллы:
    46
    Касаемо самого метода getNearbyEntities, метод достаточно хорош, на тех условиях, что никаких ограничений мы терпеть не собираемся.Конечно, метод достаточно ресурсозатратный, поэтому где можно, от его использования стоит отказаться.Если всё же, частого использования этого метода не избежать, но можно потерпеть некоторые ограничения, то стоит написать свой.Можно достать ключевые методы получения сущности из nms, написать свой метод просчёта координат, не учитывая координату Y.Можно сделать радиус не блочный, а чанковый.То есть, получать всех сущностей в чанке, не учитывая блочное расстояние.В методе выше, например, получают всех сущностей в чанке, но отсекают по радиусу, если для нас это не критично, то можно убрать.Опять таки, нужно терпеть разные ограничения, если это возможно.Изменив где-то в коде double на float, ситуация кардинально не изменится.Как пример, Влад в своем ядре UltraMineCore переписал алгоритм спавна животных, что позволило существенно снизить нагрузку на сервер, но, животные под крышей не спавнились.На счёт тестов, стоит учитывать то, что JIT имеет одну неприятную особенность - холодный старт.То есть, при первой итерации метода, время выполнения обычно больше, чем при последующих.Я не уверен, что холодный старт играет тут какую-либо роль, но на всякий случай стоит провести несколько итераций и вычислить среднее(с учётом первой итерации или без).На днях соберу несколько вариантов аналога с разных источников, накидаю своих(возможно даже на основе найденных) и проведу поверхностные тесты, о результатах сообщу в этой теме.
     
  7. CoolBoy

    CoolBoy Активный участник Пользователь

    Баллы:
    96
    Skype:
    thecoolboy2070
    Имя в Minecraft:
    CoolBoy
    Код:
    public static Set<Entity> getEntitiesNearLocation(Location center, int radius) 
    {
        Set<Entity> entities = new HashSet<> ();
    
        for (Entity entity : center.getWorld().getEntities()) 
        {
            if (isEntityInRadius(center, radius, entity))
            {
                entities.add(entity);
            }
        }
    
        return entities;
    }
    
    public static boolean isEntityInRadius(Location center, double radius, Entity entity) 
    {
        return isInRadius(center, entity.getLocation(), radius);
    }
    
    public static boolean isInRadius(Location center, Location loc, double radius) 
    {
        if (!loc.getWorld().equals(center.getWorld())) 
        {
            return false;
        }
    
        return center.distanceSquared(loc) <= (radius * radius);
    }
    
     

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