Jump to content
Search In
  • More options...
Find results that contain...
Find results in...

[1.18.1] Preferred way of programatically breaking blocks


NJSwede
 Share

Recommended Posts

Hi!

Java veteran, but new to modding. I'm working on ny very first mod experiments and I'm playing with increasing the reach of a pickaxe by following veins of ore and other fun things. 

Whenever I break a block and have a certain custom enchantment on my pickaxe, I want to break a few additional nearby blocks as well. Seems simple enough. I also want it to kind of "ripple" through the environment, so my thought was to put the blocks to be destroyed on a queue and let a tick event subscriber pick them up, one for each tick.

I have this:

@SubscribeEvent
  public static void onTick(final TickEvent e) {
    if (MegaMinerEvents.queue.isEmpty()) {
      return;
    }
    final BlockToBreak b = MegaMinerEvents.queue.removeFirst();
    final BlockState bs = b.world.getBlockState(b.pos);
    bs.getBlock()
        .playerDestroy(b.player.getLevel(), b.player, b.pos, bs, null, b.player.getMainHandItem());
    b.player.getLevel().removeBlock(b.pos, false);
  }

 

As you can see, I simply pop a block from the queue every tick and break it. It sort of works. 

However, I'm wondering if Block::playerDestroy is the right method to call. First of all, it doesn't actually remove the block. Second, it doesn't trigger any events from what I can see. The vanilla game itself is using ServerPlayerGameMode::destroyBlock(), but that method isn't accessible from any context I'm in.

So the question is: Is Block::playerDestroy the right method to use?
What other things, like sending events and checking things to I need to do if I use that method?
Also, is "onTick" the right place to do this?

 

Thanks!
NJSwede

Link to comment
Share on other sites

What is MegaMinerEvents? What is MegaMiner for that matter?

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

31 minutes ago, Draco18s said:

What is MegaMinerEvents? What is MegaMiner for that matter?

MegaMiner is just my playground mod. Here's the entire MegaMinerEvents class. It's just a static event receiver.

 

package nu.rydin.explodingarrows.common.events;

import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import nu.rydin.explodingarrows.common.Main;
import nu.rydin.explodingarrows.common.enchantments.ModEnchantments;

import java.util.LinkedList;

@Mod.EventBusSubscriber(modid = Main.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE)
public class MegaMinerEvents {
  private static final class BlockToBreak {

    private final BlockPos pos;

    private final Player player;

    public BlockToBreak(final BlockPos pos, final Player player) {
      this.pos = pos;
      this.player = player;
    }
  }

  private static final LinkedList<BlockToBreak> queue = new LinkedList<>();

  @SubscribeEvent
  public static void onBreakBlock(final BlockEvent.BreakEvent e) {
    final LevelAccessor world = e.getWorld();
    if (world.isClientSide()) {
      return;
    }
    for (final Tag t : e.getPlayer().getMainHandItem().getEnchantmentTags()) {
      final CompoundTag ct = (CompoundTag) t;
      if (ct.getString("id")
          .equals(ModEnchantments.MEGA_MINER.get().getRegistryName().toString())) {
        MegaMinerEvents.mineNeighborhood(e.getPos(), e.getPlayer(), e.getState().getBlock());
      }
    }
  }

  @SubscribeEvent
  public static void onTick(final TickEvent.ServerTickEvent e) {
    if (MegaMinerEvents.queue.isEmpty()) {
      return;
    }
    final BlockToBreak b = MegaMinerEvents.queue.removeFirst();
    final Level world = b.player.level;
    final BlockState bs = world.getBlockState(b.pos);
    bs.getBlock().playerDestroy(world, b.player, b.pos, bs, null, b.player.getMainHandItem());
    world.removeBlock(b.pos, true);
    // MegaMinerEvents.mineNeighborhood(b.pos, b.player, bs.getBlock());
    System.out.println(MegaMinerEvents.queue.size());
  }

  private static void mineNeighborhood(
      final BlockPos pos, final Player player, final Block blockType) {
    final float x0 = pos.getX();
    final float y0 = pos.getY();
    final float z0 = pos.getZ();
    for (float z = z0 - 1.0F; z <= z0 + 1; z += 1.0) {
      for (float y = y0 - 1.0F; y <= y0 + 1; y += 1.0) {
        for (float x = x0 - 1.0F; x <= x0 + 1; x += 1.0) {
          final BlockState b = player.getLevel().getBlockState(pos);
          if (b.is(blockType)) {
            MegaMinerEvents.queue.addLast(new BlockToBreak(pos, player));
          }
        }
      }
    }
  }
}

 

Edited by NJSwede
Link to comment
Share on other sites

You should absolutely call ForgeHooks.canHarvestBlock(state, entityPlayer, world, pos) before attempting to do anything to a block. If the return is false, skip that block.

As for the proper way to dig it out, dig around in the vanilla blocks class and look for where ForgeHooks.modifyLoot is called. Once you find that spot you might have to go up the call stack a little bit before you find the exact thing to call, and if might be several things. Been a while since I looked at it.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

It turned out that ServerPlayerGameMode was accessible after all. All I had to do was to cast my player to a ServerPlayer and ask for the game mode. Calling destroyBlock on that class seems to do all the proper tests and fire the right events. It all works now! Now I can mine an entire vein of diamonds or fell an entire tree in one stroke. Whohooo! :)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Currently, I'm trying to figure out how to read in data from a custom datapack.  The intention is to have the Item have a reference to this pack (IE "modname:material/materialname") as an NBT tag, and i would overwrite some use functions based off of that.  How should I go about reading in the data from the datapack?
    • Game version is 1.16.5, no mods were installed, using Java8 while it happened. And I have multiple different versions of Java including Java8, 11, 12, 13, 14, 15, 16, 18 were installed in my system, but there is only Java8's path inside the environment variable. Could them be one of the reasons? I'm new here so I almost don't know anythings about forge server. Please tell me if you need other files or logs. Following is the output inside CMD after I open the "start.bat": ECHO 处于打开状态。 C:\Users\30121\Desktop\N0u3_OL_server>"C:\Program Files\Java\jre1.8.0_321\bin\java.exe" -Xms2G -Xmx2G -jar forge-1.16.5-36.2.35.jar nogui 2022-05-25 12:42:52,637 main ERROR Error processing element Queue ([Appenders: null]): CLASS_NOT_FOUND 2022-05-25 12:42:52,670 main WARN Advanced terminal features are not available in this environment 2022-05-25 12:42:52,709 main ERROR Unable to locate appender "ServerGuiConsole" for logger config "root" [12:42:52] [main/INFO] [cp.mo.mo.Launcher/MODLAUNCHER]: ModLauncher running: args [--gameDir, ., --launchTarget, fmlserver, --fml.forgeVersion, 36.2.35, --fml.mcpVersion, 20210115.111550, --fml.mcVersion, 1.16.5, --fml.forgeGroup, net.minecraftforge, nogui] [12:42:52] [main/INFO] [cp.mo.mo.Launcher/MODLAUNCHER]: ModLauncher 8.1.3+8.1.3+main-8.1.x.c94d18ec starting: java version 1.8.0_321 by Oracle Corporation [12:42:53] [main/INFO] [ne.mi.fm.lo.FixSSL/CORE]: Added Lets Encrypt root certificates as additional trust Exception in thread "main" [12:42:53] [main/INFO] [STDERR/]: [java.lang.ThreadGroup:uncaughtException:-1]: java.lang.NoClassDefFoundError: com/google/common/base/Preconditions [12:42:53] [main/INFO] [STDERR/]: [java.lang.ThreadGroup:uncaughtException:-1]:         at org.spongepowered.asm.service.modlauncher.MixinTransformationHandler.offer(MixinTransformationHandler.java:67) [12:42:53] [main/INFO] [STDERR/]: [java.lang.ThreadGroup:uncaughtException:-1]:         at org.spongepowered.asm.service.modlauncher.MixinServiceModLauncher.offer(MixinServiceModLauncher.java:162) [12:42:53] [main/INFO] [STDERR/]: [java.lang.ThreadGroup:uncaughtException:-1]:         at org.spongepowered.asm.launch.MixinBootstrap.offerInternals(MixinBootstrap.java:227) [12:42:53] [main/INFO] [STDERR/]: [java.lang.ThreadGroup:uncaughtException:-1]:         at org.spongepowered.asm.launch.MixinBootstrap.start(MixinBootstrap.java:148) [12:42:53] [main/INFO] [STDERR/]: [java.lang.ThreadGroup:uncaughtException:-1]:         at org.spongepowered.asm.launch.MixinTransformationServiceAbstract.initialize(MixinTransformationServiceAbstract.java:88) [12:42:53] [main/INFO] [STDERR/]: [java.lang.ThreadGroup:uncaughtException:-1]:         at cpw.mods.modlauncher.TransformationServiceDecorator.onInitialize(TransformationServiceDecorator.java:68) [12:42:53] [main/INFO] [STDERR/]: [java.lang.ThreadGroup:uncaughtException:-1]:         at cpw.mods.modlauncher.TransformationServicesHandler.lambda$initialiseTransformationServices$7(TransformationServicesHandler.java:107) [12:42:53] [main/INFO] [STDERR/]: [java.lang.ThreadGroup:uncaughtException:-1]:         at java.util.HashMap$Values.forEach(Unknown Source) [12:42:53] [main/INFO] [STDERR/]: [java.lang.ThreadGroup:uncaughtException:-1]:         at cpw.mods.modlauncher.TransformationServicesHandler.initialiseTransformationServices(TransformationServicesHandler.java:107) [12:42:53] [main/INFO] [STDERR/]: [java.lang.ThreadGroup:uncaughtException:-1]:         at cpw.mods.modlauncher.TransformationServicesHandler.initializeTransformationServices(TransformationServicesHandler.java:59) [12:42:53] [main/INFO] [STDERR/]: [java.lang.ThreadGroup:uncaughtException:-1]:         at cpw.mods.modlauncher.Launcher.run(Launcher.java:76) [12:42:53] [main/INFO] [STDERR/]: [java.lang.ThreadGroup:uncaughtException:-1]:         at cpw.mods.modlauncher.Launcher.main(Launcher.java:66) [12:42:53] [main/INFO] [STDERR/]: [java.lang.ThreadGroup:uncaughtException:-1]:         at net.minecraftforge.server.ServerMain$Runner.runLauncher(ServerMain.java:49) [12:42:53] [main/INFO] [STDERR/]: [java.lang.ThreadGroup:uncaughtException:-1]:         at net.minecraftforge.server.ServerMain$Runner.access$100(ServerMain.java:46) [12:42:53] [main/INFO] [STDERR/]: [java.lang.ThreadGroup:uncaughtException:-1]:         at net.minecraftforge.server.ServerMain.main(ServerMain.java:43) [12:42:53] [main/INFO] [STDERR/]: [java.lang.ThreadGroup:uncaughtException:-1]: Caused by: java.lang.ClassNotFoundException: com.google.common.base.Preconditions [12:42:53] [main/INFO] [STDERR/]: [java.lang.ThreadGroup:uncaughtException:-1]:         at java.net.URLClassLoader.findClass(Unknown Source) [12:42:53] [main/INFO] [STDERR/]: [java.lang.ThreadGroup:uncaughtException:-1]:         at java.lang.ClassLoader.loadClass(Unknown Source) [12:42:53] [main/INFO] [STDERR/]: [java.lang.ThreadGroup:uncaughtException:-1]:         at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) [12:42:53] [main/INFO] [STDERR/]: [java.lang.ThreadGroup:uncaughtException:-1]:         at java.lang.ClassLoader.loadClass(Unknown Source) [12:42:53] [main/INFO] [STDERR/]: [java.lang.ThreadGroup:uncaughtException:-1]:         ... 15 more C:\Users\30121\Desktop\N0u3_OL_server>pause 请按任意键继续. . .
    • Although I am not exactly sure how a try-finally block would help (i.e. what code I should run even if a runtime exception is thrown), I have made some progress. The custom mob renders, but it does not rotate--even when I apply rotations to it before calling render(). private static boolean renderingCustomEntity = false; private static CustomEntity customEntity; private static void initializeCustomEntityIfNull(LocalPlayer localPlayer) { if (customEntity == null) { customEntity = ModEntities.CUSTOM_ENTITY.get().create(localPlayer.clientLevel); } } @SubscribeEvent public static void replaceMobModel(RenderLivingEvent.Pre<LivingEntity, EntityModel<LivingEntity>> event) { LocalPlayer localPlayer = Minecraft.getInstance().player; if (localPlayer != null && event.getEntity() instanceof Mob mob) { try { if (!renderingCustomEntity) { renderingCustomEntity = true; event.setCanceled(true); initializeCustomEntityIfNull(localPlayer); // I try to apply rotations to the custom entity before it rendered, but it still does not rotate at all. customEntity.setYRot(mob.getYRot()); customEntity.setYHeadRot(mob.getYHeadRot()); customEntity.setPose(mob.getPose()); // For some reason, the custom mob did not render when I called EntityRenderDispatcher#render. // So I called render() from EntityRenderDispatcher#getRenderer instead. Minecraft.getInstance().getEntityRenderDispatcher().getRenderer(customEntity).render( customEntity, customEntity.getYRot(), event.getPartialTick(), event.getPoseStack(), event.getMultiBufferSource(), event.getPackedLight() ); } } finally { renderingCustomEntity = false; } } } What would I be missing? Thank you for the help.
    • https://ileanafilio.com/cong-ty-co-phan-dau-tu-lien-doanh-viet-anh/ https://ileanafilio.com/tu-dong-viet-hoa-dau-dong-trong-excel-2007/ https://ileanafilio.com/tai-bai-hat-yeu-lai-tu-dau/ https://ileanafilio.com/phan-ky-dau-tu-du-an/ https://ileanafilio.com/su-lua-chon-so-phan-tap-62/ https://ileanafilio.com/cong-ty-co-phan-thuong-mai-dau-tu-va-phat-trien-cong-nghe-sctt/ https://ileanafilio.com/karate-co-nguon-goc-tu-dau/ https://ileanafilio.com/tap-doan-co-khi-xay-dung-thuong-mai-dai-dung/ https://ileanafilio.com/cach-tinh-dau-tu-tai-san-co-dinh/
    • Yes, I used it. And when I deleted the unnecessary parts and ran it again, I got an error. Now when I repaired that error and ran it, it worked fine. Thanks!
  • Topics

×
×
  • Create New...

Important Information

By using this site, you agree to our Privacy Policy.