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

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

Discussion in 'Разработка плагинов для новичков' started by Exception_Prototype, Feb 26, 2017.

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

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

    Trophy Points:
    46
    Всё таки и я задался вопросов о максимально лучшем варианте получения живности вокруг в указанном радиусе.
    Нашёл код ниже здесь. Хотелось бы узнать мнение знающих людей, а частности очень интересует мнение @AtomicInteger, ибо он очень часто упоминал о доработке стандартного getNearbyEntities().
    Code:
        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
     
    Last edited: Feb 26, 2017
  2. Хостинг MineCraft
    <
  3. Blc_Dragon

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

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

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

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

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

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

    Code:
        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 Активный участник Пользователь

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

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

    Trophy Points:
    96
    Skype:
    thecoolboy2070
    Имя в Minecraft:
    CoolBoy
    Code:
    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);
    }
    
     

Share This Page