Проверка целостности кровати на спавнпоинте (и не только)

Версия Minecraft
1.14.4
205
12
103
Всем привет. Цель предельно проста - сделать магическое зеркало из террарии в кубаче, однако и тут я столкнулся с двумя(или даже тремя) вопросами. Тему собирался писать неоднократно, но потом в голову приходило что-то вроде "А что, если..." и я уходил обратно пробовать. Сейчас, уже вдоволь напробовавшись, таки решил написать.

Magic_Mirror_%28demo%29.gif

"Код":
Java:
    @Override
    public ActionResult<ItemStack> onItemRightClick(World worldIn, PlayerEntity playerIn, Hand handIn) {
        ItemStack itemstack = playerIn.getHeldItem(handIn);
        BlockPos spawnPoint = playerIn.getBedLocation(playerIn.getSpawnDimension());
        if (!playerIn.abilities.isCreativeMode) {
            playerIn.getCooldownTracker().setCooldown(this, 100);
        }

        if (spawnPoint == null) {
            playerIn.sendMessage(new TranslationTextComponent("block.minecraft.bed.not_valid"));
            return new ActionResult<>(ActionResultType.FAIL, itemstack);
        } else {
            worldIn.playSound(playerIn, playerIn.posX, playerIn.posY, playerIn.posZ, ModSounds.TELEPORT, SoundCategory.PLAYERS, 1.0F, 1.0F);
            if (!worldIn.isRemote) {
                playerIn.setPositionAndUpdate(spawnPoint.getX(), spawnPoint.getY(), spawnPoint.getZ());
            }
            return new ActionResult<>(ActionResultType.SUCCESS, itemstack);
        }
    }

Что должен делать предмет: При клике ПКМ с небольшой задержкой телепортирует игрока к его кровати. если кровати нет - крякает об этом в чат.

Имеющиеся проблемы:
1. Если кровать еще ни разу не была установлена, игрока, как и должно быть, не телепортирует к точке спавна, однако звук телепортации всё равно воспроизводится, хотя не должен, поскольку телепортация не происходит.
2. После установки кровати всё работает подобно ожиданиям, однако при разрушении кровати игрока всё ещё телепортирует к предыдущему её местоположению. Нужно как-то при нажатии ПКМ обновлять её позицию.

Дополнительные задачи:
1. Необходимо реализовать задержку срабатывания зеркала. Т.е. нажал ПКМ, прошло пару секунд - игрока телепортировало. Я пока не искал как это реализовать,так как не решил предыдущие проблемы. Но если кто-то подскажет - буду благодарен.

P.S. - Как можно заметить по коду, я там уже столько всего наворотил в тщетных попытках решения имеющихся вопросов, что сам запутался.
 
Последнее редактирование:
Решение
1. Весь метод оберни в !world.isRemote
2. В игроке, вроде, есть метод verifyBedLocation. Там проверяется что кровать рил стоит и не сломана.

1. Пишешь в нбт стака кулдаун, в апдейте считаешь время и тепаешь.

tox1cozZ

aka Agravaine
8,454
598
2,890
1. Весь метод оберни в !world.isRemote
2. В игроке, вроде, есть метод verifyBedLocation. Там проверяется что кровать рил стоит и не сломана.

1. Пишешь в нбт стака кулдаун, в апдейте считаешь время и тепаешь.
 
205
12
103
1. Весь метод оберни в !world.isRemote
Если я верно понял, так:

Java:
    @Override
    public ActionResult<ItemStack> onItemRightClick(World worldIn, PlayerEntity playerIn, Hand handIn) {
        ItemStack itemstack = playerIn.getHeldItem(handIn);
        if (!worldIn.isRemote) {
            BlockPos spawnPoint = playerIn.getBedLocation(playerIn.getSpawnDimension());

            if (!playerIn.abilities.isCreativeMode) {
                playerIn.getCooldownTracker().setCooldown(this, 100);
            }

            if (spawnPoint == null) {
                playerIn.sendMessage(new TranslationTextComponent("block.minecraft.bed.not_valid"));
                return new ActionResult<>(ActionResultType.FAIL, itemstack);
            } else {
                worldIn.playSound(playerIn, playerIn.posX, playerIn.posY, playerIn.posZ, ModSounds.TELEPORT, SoundCategory.PLAYERS, 1.0F, 1.0F);
                playerIn.setPositionAndUpdate(spawnPoint.getX(), spawnPoint.getY(), spawnPoint.getZ());
            }
        }
        return new ActionResult<>(ActionResultType.SUCCESS, itemstack);
    }

Исходя из этого:
Звук на сервер воспроизводиться не должен, насколько мне известно, и с такой обёрткой оно звук вообще не воспроизводит.
Итемстак вынес за !isRemote чтоб нижний return возвращал результат действия нормально.

2. В игроке, вроде, есть метод verifyBedLocation. Там проверяется что кровать рил стоит и не сломана.
Возможно, я не там ищу, но найти не могу.


1. Пишешь в нбт стака кулдаун, в апдейте считаешь время и тепаешь.
Спасибо, буду пробовать.
 

tox1cozZ

aka Agravaine
8,454
598
2,890
Звук на сервер воспроизводиться не должен, насколько мне известно, и с такой обёрткой оно звук вообще не воспроизводит.
Метод в мире кривой, он воспроизводит звук всем кроме текущего игрока. И там не воспроизведение на сервере, а отправка пакета всем рядом со звуком. Посмотри в снежке, например, как воспроизводится звук бросания.

Возможно, я не там ищу, но найти не могу.
В 1.12.2 так: EntityPlayer#getBedSpawnLocation. В 1.14 без понятия, ищи похожее...
 
205
12
103
Метод в мире кривой, он воспроизводит звук всем кроме текущего игрока. И там не воспроизведение на сервере, а отправка пакета всем рядом со звуком. Посмотри в снежке, например, как воспроизводится звук бросания.
Отлично, этот вопрос решен. Звук воспроизвожу следующим образом:
Java:
worldIn.playSound((PlayerEntity)null, playerIn.posX, playerIn.posY, playerIn.posZ, ModSounds.TELEPORT, SoundCategory.NEUTRAL, 1.0F, 1.0F);
Не совсем понимаю суть сего каста, ну да ладно. Вечером разберу. Сейчас буду пробовать решить второй вопрос.
 
205
12
103
В 1.12.2 так: EntityPlayer#getBedSpawnLocation. В 1.14 без понятия, ищи похожее...
Вот, что удалось найти:

IForgeBlockState#getBedSpawnPosition:
    /**
     * Returns the position that the sleeper is moved to upon
     * waking up, or respawning at the bed.
     *
     * @param world The current world
     * @param pos Block position in world
     * @param sleeper The sleeper or camera entity, null in some cases.
     * @return The spawn position
     */
    default Optional<Vec3d> getBedSpawnPosition(EntityType<?> type, IWorldReader world, BlockPos pos, @Nullable LivingEntity sleeper)
    {
        return getBlockState().getBlock().getBedSpawnPosition(type, getBlockState(), world, pos, sleeper);
    }


PlayerEntity#getBedLocation:
   @Deprecated //Forge: Use Dimension sensitive version
   public BlockPos getBedLocation() {
      return getBedLocation(this.dimension);
   }

   /**
    * A dimension aware version of getBedLocation.
    * @param dim The dimension to get the bed spawn for
    * @return The player specific spawn location for the dimension.  May be null.
    */
   public BlockPos getBedLocation(net.minecraft.world.dimension.DimensionType dim) {
      return dim == net.minecraft.world.dimension.DimensionType.OVERWORLD ? spawnPos : spawnPosMap.get(dim.getRegistryName());
   }

Первый вариант больше похож на правду, сейчас попробую заюзать, правда хз как :D
 
205
12
103
2. После установки кровати всё работает подобно ожиданиям, однако при разрушении кровати игрока всё ещё телепортирует к предыдущему её местоположению. Нужно как-то при нажатии ПКМ обновлять её позицию.
С этим пока грустно - всё ещё не получается.
Либо методы из предыдущего сообщения не подходят, либо я не догоняю.
 
7,099
324
1,509
У тебя в предмете запоминается спавн-поинт? Зачем? Просто каждый раз получай его из мира. Если кровать сломается, спавн-поинт сам сетнется на общий спавн
 
205
12
103
У тебя в предмете запоминается спавн-поинт?
Попробовал запоминать только после ручной проверки, не помогло.

Чтоб не создавать каждый раз новый BlockPos при получении кординат x,y и z во время вызова setPositionAndUpdate. По идее, оно при каждом ПКМ перезаписывает эту координату для дальнейшего использования.

Тс, глянь в респавне игрока код
Смотрю, еще раз смотрю, а потом еще раз - ничего полезного не вижу. Сейчас пытаюсь дебагом методом тыка найти нужный метод из класса PlayerEntity.
 
7,099
324
1,509
Чтоб не создавать каждый раз новый BlockPos при получении кординат x,y и z во время вызова setPositionAndUpdate
Щас бы париться из-за единичных аллокаций в бакэнде :m_faceplam:
~~~
Ответ на реакцию "Чего?":
Того! Одна аллокация объекта, которая происходит один раз за телепорт картину не изменит. Минисруфт и без тебя насрет в кучу(в прямом смысле, куча - способ огранизации памяти в jvm).
Бояться аллокаций надо, если твой код выполняется много раз за маленький промежуток времени или если это код рендера(очистка кучи сборщиком мусора может вызывать фризы)
 
Последнее редактирование:
Сверху