1. Этот сайт использует файлы cookie. Продолжая пользоваться данным сайтом, Вы соглашаетесь на использование нами Ваших файлов cookie. Узнать больше.
  2. Вы находитесь в сообществе Rubukkit. Мы - администраторы серверов Minecraft, разрабатываем собственные плагины и переводим на различные языки плагины наших коллег из других стран.
    Скрыть объявление
Скрыть объявление
В преддверии глобального обновления, мы проводим исследования, которые помогут нам сделать опыт пользования форумом ещё удобнее. Помогите нам, примите участие!

Помогите Создание NPC

Тема в разделе "Разработка плагинов для новичков", создана пользователем HaloSpartan, 14 сен 2019.

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

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

    Баллы:
    66
    Привет форумчане!
    Мне нужна помощь по поводу создания NPC(игрок), как можно это сделать?
    Подскажите как это можно сделать, да и так чтобы с ним можно было взаимодействовать(допустим ПКМ).
    По форумам лазил, не нашёл нужной ин-фы.
    Заранее благодарю
     
  2. imDaniX

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

    Баллы:
    96
    Имя в Minecraft:
    imDaniX
    Понадобится ProtocolLib(либо ползать в nms). Ставишь моба, который в последствии будет твоим НИПом. Ловишь пакет с этим мобом, посылаешь редактированный с тем же entity-id, профит. На словах то просто, но если не работал с этим никогда - придется помучаться.
    А можно не париться и использовать Lib's Disguises с его API, и все скатывается до DisguiseAPI.disguiseToAll(твойМоб, new PlayerDisguise("Пример"))
    Готовое решение - Citizens, но каждый раз, когда я сам ставил этот плагин на сервер, он начинал лагать. Впрочем, это было 5 лет назад, и наверняка всё переменилось.
     
  3. Dymeth

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

    Баллы:
    98
    Имя в Minecraft:
    Dymeth
    Обновлено:
    Создал отдельную тему с актуальной информацией по созданию NPC в игре: https://rubukkit.org/threads/190265

    Citizens - самый простой способ вообще, если достаточно стоящих на месте моделек, по которым нужно отслеживать нажатия.

    Если модельки должны рандомно передвигаться по местности - то спаунить, например, жителей и менять им тип на игроков при помощи LibsDisguises. Пробовал ещё iDisguise, но он более багованый и с меньшим количеством возможностей.

    Если нужен кастомный интеллект - то тут:
    1) Либо Citizens, где нужно полностью самому реализовывать интеллект при помощи Bukkit
    2) Либо BKCommonLib, где вроде как готовые блоки интеллекта (как в самой игре). Но это не точно - сам не использовал
    3) Либо NMS + рефлексия. Придётся использовать готовые блоки интеллекта или реализовывать свои goalSelector'ы и targetSelector'ы

    Сейчас всё в порядке, да.
     
    Последнее редактирование: 10 янв 2024
  4. SaMEC

    SaMEC Старожил Пользователь

    Баллы:
    173
    Skype:
    support.meedway
    Имя в Minecraft:
    Nick
    Код:
    {
              Location loc = new Location(Bukkit.getWorld("world"), 99.5, 87, 97.5, 1, 0);
                Villager king = (Villager)loc.getWorld().spawnEntity(loc, EntityType.VILLAGER);
                king.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 999999999, 10, true, false));
                king.addPotionEffect(new PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, 999999999, 5, true, false));
                king.setCustomNameVisible(true);
                king.setCustomName("§bКороль");
                king.setCollidable(false);
                king.setAI(false);
                king.resetMaxHealth();
            }
    
      @EventHandler
      public void onPlayerInteractEntity(PlayerInteractEntityEvent e)
      {
        if (!(e.getRightClicked() instanceof Villager)) return;
        Entity ent = e.getRightClicked();
        if ((ent instanceof Villager)) {
          Player p = e.getPlayer();
          if(ent.getCustomName() == null)return;
          if (ent.getCustomName().equalsIgnoreCase("§bКороль"))
          {
            e.setCancelled(true);
            p.sendMessage("Здравствуй HaloSpartan");
        }
       }
    }
     
  5. Dymeth

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

    Баллы:
    98
    Имя в Minecraft:
    Dymeth
    Человеку нужна модельная игрока, а не житель.
    Думаю, жителя он и сам умеет спаунить.
    Да и по имени проверять нажатие по мобу - такое себе
     
  6. SaMEC

    SaMEC Старожил Пользователь

    Баллы:
    173
    Skype:
    support.meedway
    Имя в Minecraft:
    Nick
  7. Автор темы
    HaloSpartan

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

    Баллы:
    66
    Видел, пробовал сам что то сделать, ничего не вышло.
     
  8. Автор темы
    HaloSpartan

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

    Баллы:
    66
    Сможешь просветить по 3-ему пункту? Хотелось бы узнать как всё самому сделать
     
  9. Dymeth

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

    Баллы:
    98
    Имя в Minecraft:
    Dymeth
    Обновлено:
    Создал отдельную тему с актуальной информацией по созданию NPC в игре: https://rubukkit.org/threads/190265

    Сложно тебе будет начинать сразу с NMS. Обычно новички начинают как раз с изучения библиотек. Если функционала недостаточно - уже лезут в НМС.
    Более того, при использовании NMS тебе придётся вручную переписывать код под каждую новую версию игры.


    Если так хочешь NMS - разберись сначала со статическими NPC из видоса выше.
    Если не получается - конкретизируй, в чём именно проблема.


    Ну а дальше... Пристёгивай ремни, мы отправляемся в ад.

    Берём в зубы IDEA со встроенным fernflower и идём декомпилировать классы ядра и смотреть, как реализован тот или иной моб.
    Названия классов энтити в NMS имеют вид "EntityМоб". Например, EntitySpider.
    Для примера копируем содержимое класса и переделываем под себя.

    Например вот так:
    PHP:
    import net.minecraft.server.v1_some.*;

    public class 
    CustomSpider extends EntitySpider {
        protected 
    CustomSpider(World world) {
            
    super(world);
        }

        @
    Override
        
    protected void n() {
            
    this.goalSelector.a(1, new PathfinderGoalFloat(this));
            
    this.goalSelector.a(3, new PathfinderGoalLeapAtTarget(this0.4F));
            
    this.goalSelector.a(4, new PathfinderGoalSpiderMeleeAttack(this));
            
    this.goalSelector.a(5, new PathfinderGoalRandomStrollLand(this0.8D));
            
    this.goalSelector.a(6, new PathfinderGoalLookAtPlayer(thisEntityHuman.class, 8.0F));
            
    this.goalSelector.a(6, new PathfinderGoalRandomLookaround(this));
            
    this.targetSelector.a(1, new PathfinderGoalHurtByTarget(thisfalse));
            
    this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(thisEntityPlayer.class, true));
        }

        static class 
    PathfinderGoalSpiderMeleeAttack extends PathfinderGoalMeleeAttack {
            
    PathfinderGoalSpiderMeleeAttack(EntityCreature creature) {
                
    super(creature1.0Dtrue);
            }

            public 
    boolean b() { //needNavigatePath
                
    float f this.a.az();
                if (
    >= 0.5F && this.a.getRandom().nextInt(100) == 0) {
                    
    this.a.setGoalTarget(null);
                    return 
    false;
                } else {
                    return 
    super.b();
                }
            }

            protected 
    double a(EntityLiving entityliving) {
                return (double) (
    4.0F entityliving.width);
            }
        }
    }

    Можешь заходить в различные классы блоков ИИ (например, PathfinderGoalRandomLookaround) и смотреть, как они работают. При аналогии можешь делать свои.

    Как теперь заспаунить энтити, который будет работать при помощи нашего класса?

    Есть два пути - "вручную" и рефлексией.
    Первый вариант работает быстрее, второй более красивый + универсальный + с потенциалом поддержки мультиверсионности.

    В обоих случаях нам понадобится следующий метод:
    PHP:
        private org.bukkit.entity.Entity initNmsEntity(Entity nmsEntityLocation location) {
            
    nmsEntity.setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
            
    nmsEntity.setPositionRotation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
            ((
    CraftWorldlocation.getWorld()).getHandle().addEntity(nmsEntityCreatureSpawnEvent.SpawnReason.CUSTOM);
            return 
    nmsEntity.getBukkitEntity();
        }


    Вручную будет примерно так так:
    PHP:
        public org.bukkit.entity.Entity spawnNmsEntity(EntityType bukkitTypeLocation location) {
            
    WorldServer nmsWorld = ((CraftWorldlocation.getWorld()).getHandle();
            switch (
    bukkitType) {
                case 
    SPIDER:
                    return 
    this.initNmsEntity(new NmsAggressiveSpider(nmsWorld), location);
                default:
                    throw new 
    IllegalArgumentException("Неподдерживаемый тип энтити");
            }
        }

    Рефлексией будет примерно так:
    PHP:
        private Map<Class<? extends org.bukkit.entity.Entity>, Constructor<? extends Entity>> nmsConstructors = new HashMap<>();

        private 
    void registerNmsEntity(Class<? extends org.bukkit.entity.EntitybukkitClass, Class<? extends Entityclazzthrows NoSuchMethodException {
            
    Constructor<? extends Entityconstructor clazz.getDeclaredConstructor(World.class);
            
    constructor.setAccessible(true);
            
    this.nmsConstructors.put(bukkitClassconstructor);
        }

    Сам процесс регистрации (нужно будет вызывать один раз при запуске сервера):
    this.registerNmsEntity(Spider.class, CustomSpider.class);
    На самом деле, кэшировать конструкторы можно по мере необходимости - тут кому как нравится, разницы особо нет.

    PHP:
        private org.bukkit.entity.Entity spawnNmsEntity(Class<? extends org.bukkit.entity.EntitybukkitClassLocation location) {
            try {
                
    WorldServer nmsWorld = ((CraftWorldlocation.getWorld()).getHandle();
                
    Entity nmsEntity this.nmsConstructors.get(bukkitClass).newInstance(nmsWorld);
                return 
    this.initNmsEntity(nmsEntity);
            } catch (
    Exception e) {
                throw new 
    RuntimeException("Не удалось заспаунить энтити"e);
            }
        }


    P.S. Есть для тебя одно предложение. Если интересно - черкани в ЛС на форуме или по одному из контактов на Dymeth.ru
     
    Последнее редактирование: 10 янв 2024
  10. alexandrage

    alexandrage Старожил Пользователь

    Баллы:
    173
    Citizens api. Там нпс с полный взаимодействием.
     
  11. alexandrage

    alexandrage Старожил Пользователь

    Баллы:
    173
    Да там есть готовый интелект копипаст с ванилы, в котором еще и свое можно внедрить.
     

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