Solved Setting thousands of blocks in a matter of seconds?

Discussion in 'Plugin Development' started by ZeusAllMighty11, Apr 21, 2013.

Thread Status:
Not open for further replies.
  1. Offline

    ZeusAllMighty11

    So I've been looking at NMS Fast

    But unfotunately, desht has changed the provided github source and is now scattered between projects, and in those, in separate classes.


    I've figured out how to retrieve and set the blocks, but I need help sending the player the necessary information to see the new set blocks -- meaning lighting

    Code:
     
    package me.zeus.TestPlugin;
     
     
    import org.bukkit.Chunk;
    import org.bukkit.Location;
    import org.bukkit.Material;
    import org.bukkit.block.Block;
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandSender;
    import org.bukkit.craftbukkit.v1_5_R2.CraftChunk;
    import org.bukkit.craftbukkit.v1_5_R2.entity.CraftPlayer;
    import org.bukkit.entity.Player;
    import org.bukkit.plugin.java.JavaPlugin;
     
     
     
    public class Main extends JavaPlugin {
     
        @Override
        public void onEnable()
        {
     
        }
     
        private void setBlockFast(Block b, int typeId, byte data)
        {
            Chunk c = b.getChunk();
            net.minecraft.server.v1_5_R2.Chunk chunk = ((CraftChunk) c).getHandle();
            chunk.a(b.getX() & 15, b.getY(), b.getZ() & 15, typeId, data);
        }
     
        private void sendChanges(Player p){
            // ?????????????
        }
        
        public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args)
        {
            if (cmd.getName().equalsIgnoreCase("test"))
            {
                if (sender instanceof Player && sender.isOp())
                {
                    Player p = (Player) sender;
                    Location loc = p.getLocation();
     
                    for (int i = 0; i < 10; i++)
                    {
                        Location newLoc = new Location(loc.getWorld(), loc.getX() + i, loc.getY(), loc.getZ() + i);
                        setBlockFast(p.getWorld().getBlockAt(newLoc), Material.WOOL.getId(), (byte) 0);
                    }
                    sendChanges(p);
                }
            }
            return false;
        }
    }
    
    How to do?
     
  2. Offline

    Tzeentchful

    Here is the method i use from desht.
    Code:java
    1.  
    2. public static void sendClientChanges(Location center, List<Chunk> chunks) {
    3. int threshold = (Bukkit.getServer().getViewDistance() << 4) + 32;
    4. threshold = threshold * threshold;
    5.  
    6. List<net.minecraft.server.v1_4_R1.ChunkCoordIntPair> pairs = new ArrayList<net.minecraft.server.v1_4_R1.ChunkCoordIntPair>();
    7. for (Chunk c : chunks) {
    8. pairs.add(new net.minecraft.server.v1_4_R1.ChunkCoordIntPair(c.getX(), c.getZ()));
    9. }
    10.  
    11. for (Player player : center.getWorld().getPlayers()) {
    12. int px = player.getLocation().getBlockX();
    13. int pz = player.getLocation().getBlockZ();
    14. if ((px - center.getX()) * (px - center.getX()) + (pz - center.getZ()) * (pz - center.getZ()) < threshold) {
    15. queueChunks(((org.bukkit.craftbukkit.v1_4_R1.entity.CraftPlayer) player).getHandle(), pairs);
    16. }
    17. }
    18. }
    19.  
    20. @SuppressWarnings("unchecked")
    21. private static void queueChunks(net.minecraft.server.v1_4_R1.EntityPlayer ep, List<net.minecraft.server.v1_4_R1.ChunkCoordIntPair> pairs) {
    22. Set<net.minecraft.server.v1_4_R1.ChunkCoordIntPair> queued = new HashSet<net.minecraft.server.v1_4_R1.ChunkCoordIntPair>();
    23. for (Object o : ep.chunkCoordIntPairQueue) {
    24. queued.add((net.minecraft.server.v1_4_R1.ChunkCoordIntPair) o);
    25. }
    26. for (net.minecraft.server.v1_4_R1.ChunkCoordIntPair pair : pairs) {
    27. if (!queued.contains(pair)) {
    28. ep.chunkCoordIntPairQueue.add(pair);
    29. }
    30. }
    31. }
    32.  
     
    TheGreenGamerHD likes this.
  3. Offline

    TheUpdater

    why dont make
    for (int i = 0; i < 1000; i+=10)
    that make an area of 1000 then get where it gona start
    at player of corse
    then set the type of i xD`?
     
  4. Offline

    ZeusAllMighty11

    Because this is WAYYYY faster
     
  5. Offline

    TheUpdater

    what is away faster?
     
  6. Offline

    ZeusAllMighty11

  7. Offline

    Tzeentchful

    TheGreenGamerHD
    I have actually found a faster method. The way your doing it still does some lighting calculations. If you want to skip 100% everything then you can do this.
    Code:java
    1. public static void setBlockSuperFast(Block b, int typeId, byte data) {
    2. Chunk c = b.getChunk();
    3. net.minecraft.server.v1_5_R2.Chunk chunk = ((org.bukkit.craftbukkit.v1_5_R2.CraftChunk) c).getHandle();
    4.  
    5. try {
    6. Field f = chunk.getClass().getDeclaredField("sections");
    7. f.setAccessible(true);
    8. ChunkSection[] sections = (ChunkSection[]) f.get(chunk);
    9. ChunkSection chunksection = sections[b.getY() >> 4];
    10.  
    11. if (chunksection == null) {
    12. if (typeId == 0)
    13. return;
    14. chunksection = sections[b.getY() >> 4] = new ChunkSection(b.getY() >> 4 << 4, !chunk.world.worldProvider.f);
    15. }
    16.  
    17. chunksection.a(b.getX() & 15, b.getY() & 15, b.getZ() & 15, typeId);
    18. chunksection.b(b.getX() & 15, b.getY() & 15, b.getZ() & 15, data);
    19.  
    20. } catch (Exception e) {
    21. e.printStackTrace();
    22. }
    23.  
    24. }
     
    Chlorek, bitWolfy and ZeusAllMighty11 like this.
  8. Offline

    gomeow

    But wait! There will a method in CB to do this soon hopefully

    Icyene

    It would use the Bukkit API alone :D

    TheUpdater
    I don't think you understand the point of what he's trying to do
     
    Icyene and TheGreenGamerHD like this.
  9. Offline

    desht

    Tzeentchful has pretty much covered it - your setlBlockSuperFast() method looks interesting, but I'd be concerned about the overhead of reflection in a method that's designed to be called so frequently. Have you done some benchmarking comparisons?

    And kudos to Icyene for going ahead and getting a PR created. Something I've been too busy/lazy (delete as appropriate) to do!

    Also, just a note to clarify how I've changed my stuff on github around...

    The dhutils project is a collection of common stuff I use in all my plugins. I shade it in via Maven when I build them. After the CraftBukkit versioning changes, I made some further changes to dhutils to abstract out the access to the NMS code (pretty much as described by mbaxter in this post: http://forums.bukkit.org/threads/support-multiple-minecraft-versions-with-abstraction-maven.115810/)

    Looking at https://github.com/desht/dhutils, there is:
    • Lib - most of the library code is now under here
    • API - provides the NMSAbstraction interface to the NMS methods included in dhutils, e.g. setBlockFast(World, int, int, int, int, byte). The interface only specifies Bukkit classes/interfaces, never NMS stuff directly.
    • All other directories under there are CraftBukkit-version-specific implementations of the NMSAbstraction interface, e.g. v_1_5_R2 is the implementation for the latest obfuscation version at the time of writing.
    • Finally, in Lib is https://github.com/desht/dhutils/blob/master/Lib/src/main/java/me/desht/dhutils/nms/NMSHelper.java, a utility class which tries to find the correct implementation class for the version of CraftBukkit that the plugin is currently running on. If there's no matching implementation, an IllegalStateException is thrown.
    • Then I make a call to NMSHelper from my plugin like this: https://github.com/desht/ChessCraft...java/me/desht/chesscraft/ChessCraft.java#L122
     
    Icyene and TheGreenGamerHD like this.
  10. Offline

    ZeusAllMighty11

    Tzeentchful gomeow desht

    Thanks all of you, and I really look forward to seeing a Bukkit API version of this soon :)
     
  11. Offline

    Icyene

    :)

    /me prods desht to submit a PR containing that lighting optimization in .setTypeId that desht mentioned

    Even so, the API I've PR'd for is rather clunky by itself, since you need to keep in mind which chunk you've modified and to make sure you refresh it afterwards.
     
  12. Offline

    desht

    Alrighty!

    I've updated my mass block update stuff here:
    I'll try to get a PR created soon, but would appreciate your (and anyone else's!) comments before I do.

    The intention is for the MassBlockUpdate interface to be in Bukkit, and the CraftMassBlockUpdate implementation to go in CraftBukkit. The nms.xxx() calls in CraftMassBlockUpdate would be replaced by direct NMS calls, and the createMassBlockUpdate() method would become a method in World/CraftWorld, e.g. MassBlockUpdate mbu = world.createMassBlockUpdate(plugin);

    There's a test plugin here with some more useful information in its README: https://github.com/desht/buster and https://github.com/desht/buster/blob/master/src/main/java/me/desht/buster/buster.java has examples of how to use the API (which is pretty simple).
     
    TheGreenGamerHD likes this.
  13. Offline

    Icyene

    Amazing! One thing I noticed though: "MassBlockUpdate.RelightingStrategy.DEFERRED", maybe refactor RelightingStrategy to its own class, to prevent having to type that awfully long segment? Regardless, if this makes it into CraftBukkit I'm sure many people (myself included) will find it very useful
     
  14. Offline

    Tirelessly

    import org.whatever.plugin.MassBlockUpdate.RelightingStrategy;

    Then you can use RelightingStrategy.DEFERRED;
     
  15. Offline

    Icyene

    Yes, I am aware of that. You can even statically import DEFERRED. Just not as neat though, in my opinion.
     
  16. Offline

    xize

    this sounds really intresting, I'm looking to a smilliar method but then for obfusucate client side blocks maybe I ask to much but to be kindly can this also be added in the same pull?
     
  17. Offline

    desht

    Glad you like it. Regarding the enum, I would really prefer it to stay within MassBlockUpdate, given that its only function is to provide extra information for that interface. You can see this pattern in other places within Bukkit (look at all the enum declarations in the various events, for example). Besides as Tirelessly pointed out, you can import the enum, and even if you don't, every IDE out there gives you auto-complete anyway :)

    Not quite sure what you mean by this, but it sounds like a rather different operation to me. Not something that would belong in the same class.
     
  18. Offline

    xize

    That's true I ment a way to detect fake obfusucated blocks with light so you can update the block via state (if possible) when a player places a torch close in the area
     
  19. Offline

    ZeusAllMighty11

    .a() and .b() no longer work

    Figured it out.

    The new methods are .setTypeId() and setData()

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 1, 2016
Thread Status:
Not open for further replies.

Share This Page