Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API: Way to remove CustomBlocks faster #3445

Closed
4 tasks done
tastybento opened this issue Feb 18, 2024 · 10 comments
Closed
4 tasks done

API: Way to remove CustomBlocks faster #3445

tastybento opened this issue Feb 18, 2024 · 10 comments

Comments

@tastybento
Copy link

Terms

  • I'm using the very latest version of ItemsAdder and its dependencies.
  • I already searched on this Github page to check if the same suggestion was already reported.
  • I already searched on the plugin wiki to know if the feature is already implemented.
  • I already searched on the Discord server to know if anyone already has a solution for this or if the feature was already suggested.

Discord tag (optional)

tastybento

Describe the solution you'd like

I would like a way to obtain a collection of CustomBlocks in a World, Chunk, or in a BoundingBox, so I can iterate through them and delete the ones that need to be deleted by Location.

Is your feature request related to a problem?

Yes. I maintain the BentoBox/BSkyBlock/AcidIsland/AOneBlock, etc. plugin. It needs to delete islands which it does on a chunk by chunk basis. We have a problem where IA custom blocks remain in the world even though Blocks have been deleted. If a new player used the old space, the IA blocks could be obtained by players placing a block and then breaking it where the old one was.

Describe alternatives you've considered

Currently, I use CustomBlock.remove(location) but when run on multiple locations, e.g., a cube of size 800 x 800 x world height, it will lag the server. I've had to remove the support for ItemsAdder because I currently cannot find a streamlined way to delete the CustomBlocks. There are rarely more than a few on any one island, but I currently have to remove every location in the whole island because I have no way to find out where they are. I'd like to be able to optimize somehow, by for example, checking if there is a block at that location first, or having a way to obtain all the CustomBlocks in a World, or Chunk, etc.

The only other option is to ask admins to change deletion settings in the BentoBox config to delete chunks a lot slower than normal, e.g., 1 chunk per tick. This is just a workaround.

Additional context

The code to the IA hook in BentoBox is here: https://github.com/BentoBoxWorld/BentoBox/blob/f81354fa3e5187f87efe48f6bc72bb9f127a9f22/src/main/java/world/bentobox/bentobox/hooks/ItemsAdderHook.java#L78

Currently, it's commented out because of the lag spikes.

I have asked on your Discord on itemsadder-chat but there were no replies.

@tastybento tastybento added the type: feature request Feature request. label Feb 18, 2024
Copy link

Hello,
your report will be looked into as soon as possible.
Please do not bump this thread and don't post it on multiple platforms.

Thanks a lot for your patience.

@LoneDev6
Copy link
Collaborator

Post a link of your implementation of where you remove blocks, so that I can know how to structure the new API to fast remove blocks.
Anyway without a spark report I can't check what is exactly slow in the underlying code, but I'd bet it's the fact that the remove method sends AIR packet to the surrounding players causing overhead, I will check that in the next weeks.

@LoneDev6 LoneDev6 added this to the 3.6.3-beta-13 milestone Feb 18, 2024
@tastybento
Copy link
Author

Thanks for the quick reply.

Islands are deleted chunk by chunk. The start point is DeleteIslandChunks.java. but regeneration is done by obtaining a replacement chunk from the GameMode, which for games like BSkyBlock is just empty air chunks, and writing the blocks in a x,y,z nested loop. For other gamemodes, it may be chunks copied from a seed world. You can find the key method here that does the looping to paste the blocks and on line 203 and 204 you can find the calls I make to Slimeworld and your plugin to delete the custom blocks. Slimeworld has a similar issue, but it does have a very quick check available that enables me to query if there's a block at the location before attempting any removal. However, what would be better would be to get a collection of blocks in a chunk (or some other space), similar to how Entities/TileEntities can be obtained, and then deal with them outside of this loop. Note that island borders can be in the middle of a chunk, so I can't always just delete everything in a chunk (although I wish it was possible).

In terms of the actual block writer, it's usually done using NMS to paste the blocks, with a Bukkit fallback in the NMS version isn't available, e.g., this for 1.20.4.

@LoneDev6
Copy link
Collaborator

LoneDev6 commented Feb 19, 2024

Would a method that deletes a all the custom blocks data for a chunk or a world be what you need?
Anyway I too use NMS internally, so probably the lag is caused by packets sending on each block change in my API implementation.

@tastybento
Copy link
Author

Unfortunately it is possible for chunks to be in more than one island - admins can set islands to abut each other so that players can build right up to the edge and bridge, so deleting everything in a chunk could accidentally delete CustomBlocks in the Nextdoor island.

The ultimate would be to have a method that takes a World and a BoundingBox and delete all the CustomBlocks in that space. However, I suspect that's a bit too much wishful thinking!

If you can provide all the CustomBlocks in a Chunk or a World I could iterate over them checking their location and delete them. I don't expect there will be that many.

@tastybento
Copy link
Author

Sorry to bump, but were you able to add anything at all? If getting the CustomBlocks in a chunk is possible, that could work.

@XLordalX
Copy link

I'm also looking for a way to iterate over all custom blocks in a chunk in order to tick them.

@LoneDev6
Copy link
Collaborator

I will add some methods under CustomBlock#Advanced class.

        public static void deleteAllCustomBlocksInChunk(Chunk chunk)

        @Nullable
        public List<Location> getAllBlocksLocationsList(Chunk chunk)

        @Nullable
        public Map<String, Location> getAllBlocksLocations(Chunk chunk)

        public void runActionOnBlocks(Chunk chunk, BiConsumer<String, Location> action)

@LoneDev6
Copy link
Collaborator

Some dumb code to test the new API. Tested and working fine on 1.20.4.

@EventHandler
    private void test(AsyncPlayerChatEvent e)
    {
        if(e.getMessage().contains("deleteAllCustomBlocksInChunk2"))
        {
            CustomBlock.Advanced.deleteAllCustomBlocksInChunk(e.getPlayer().getChunk(), true, true);
        }
        else if(e.getMessage().contains("deleteAllCustomBlocksInChunk"))
        {
            CustomBlock.Advanced.deleteAllCustomBlocksInChunk(e.getPlayer().getChunk());
        }
        else if(e.getMessage().contains("getAllBlocksLocationsList"))
        {
            List<Location> list = CustomBlock.Advanced.getAllBlocksLocationsList(e.getPlayer().getChunk());
            if(list == null)
                return;
            for (int i = 0; i < list.size(); i++)
            {
                Location location = list.get(i);
                System.out.println(location);
                if(i > 10)
                {
                    System.out.println("and more...");
                    break;
                }
            }
        }
        else if(e.getMessage().contains("getAllBlocksLocations"))
        {
            @org.jetbrains.annotations.Nullable Map<Location, String> list = CustomBlock.Advanced.getAllBlocksLocations(e.getPlayer().getChunk());
            if(list == null)
                return;

            AtomicInteger i = new AtomicInteger();
            for (Map.Entry<Location, String> entry : list.entrySet())
            {
                String s = entry.getValue();
                Location location = entry.getKey();
                System.out.println(s + " | " + location);
                if (i.get() > 10)
                {
                    System.out.println("and more...");
                    break;
                }
                i.getAndIncrement();
            }
        }
        else if(e.getMessage().contains("runActionOnBlocks"))
        {
            AtomicInteger i = new AtomicInteger();
            CustomBlock.Advanced.runActionOnBlocks(e.getPlayer().getChunk(), (s, location) -> {
                System.out.println(s + " | " + location);
                if (i.get() > 10)
                {
                    System.out.println("and more...");
                    return;
                }
                i.getAndIncrement();
            });
        }
    }

@tastybento
Copy link
Author

Fantastic work! Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

No branches or pull requests

3 participants