I need help optimising plugins for my 300 player server.

Discussion in 'Plugin Development' started by DubstepCraig, Nov 6, 2012.

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


    Hey guys, I'm DubstepCraig and I run a fairly popular minecraft server. I'm trying to optimise some of my plugins to decrease lag, I have the ideas but no idea how to implement them in Java as I only know PHP and Python, If someone could help me out with this I would be eternally grateful :)


    Ps. Check it out first at www.dubcraft.org
    Boriscool22 and Hoolean like this.
  2. Offline


    Hehe... Eternally Grateful :D
  3. Offline


    What your plugins do and how they're build?
  4. Offline


    A custom spleef plugin I need to changed to spawn blocks in a more optimised way to stop the server from lagging.
  5. Offline


    I heard someday using N.M.S (net.minecraft.server) to manipulate blocks can be faster than through the Bukkit API.
  6. Offline


    It not only can be faster but is actually several hundred to thousand times faster as Bukkit recalculates the lighting after each block that was changed while using NMS one can directly manipulate the world data and then recalculate the lighting only once.
    WorldEdit for example does this and IIRC it has an API to hook into so one won't even have to do this on their own.
  7. Offline


    Thanks. Good to know that I wasn't wrong with my statement.
  8. Offline


    1. public void setBlockFast(int x, int y, int z, String world, int typeID, byte data) {
    2. Chunk c = Bukkit.getWorld(world).getChunkAt(x, z);
    3. net.minecraft.server.Chunk chunk = ((CraftChunk) c).getHandle();
    4. chunk.a(x & 15, y, z & 15, typeID, data);
    5. }
  9. Offline


    Timr, why do you do the bitwise and for x and z when setting the block? I'm not trying to say it's wrong; I'm just new to this method and I'd like to know a little bit more about it.


    I've never used the bitwise and, or any of the other bitwise operators, but wouldn't it return a boolean value?
    After a bit of digging it seems that you are using 15 as a bitmask for the x and z? Could I ask why?

    Oh, also while looking through the net.minecraft.server.Chunk code, I see that whenever they get a ChunkSection, they shift the byte right 4. If any of you know why, can you tell me?

    Apologies to OP for distracting from the thread's purpose.
  10. Offline


    Timr Interessts me too, why not x % 16?
  11. Offline


    That's fine, but you also need to ensure updates are actually sent to clients (and lighting recalculation done), or players won't see your changes until they relog.

    Either's correct, and (I admittedly haven't checked the generated bytecode) probably pretty much equal in performance. Either way the difference will be negligible.
  12. Offline


    '>>4' removes the lowest 4 bits from the block's coordinate (by shifting all other bits 4 to the right), i.e. it gets the chunk coordinates from an block within the chunk.
    The 4 removed bits are the relative coordinates of a block in a chunk, i.e. these are the bits that are masked with &15.
  13. Offline


    Why are you posting this in two forum sections? :l
  14. Offline


    Correct me if I'm wrong, but WorldEdit (unfortunately) does not use that method. It sets the blocks one by one with setTypeId. NMS setting blocks can get a speed upwards of 5000 blocks/s, while WorldEdit lags on a measly circle with a radius of 10.

    Some of the gory details can be found here.
  15. Offline


    Well you should note that the 'fast' command does not update physics ;3 (which btw calls a function with the EXACT code like the function, except the data value, and after that it calls the lighting)

    Besides that all, a small sidenote would be that I checked decompiled minecraft, and it basically does the same. First it updates the block, then it updates lighting
  16. Offline


    I took a look at the post you linked to, and I saw something that I'm a little confused about. Basically, you talked about calling the net.minecraft.server InitLighting methods. But isn't lighting rendered by the client anyway? And if I'm not wrong about that, then why would such a call be necessary?
  17. Offline


    No clue I am just reading some decompiled NMS code, Chunk.java, and I see relightBlock methods called
  18. Offline


    This is awkward. I play occasionally on Rprrr 's server, I used to have server hosting with DubstepCraig, and Timr used to play on my server, and they are all in this thread! :eek:
    Someone should make a pull request, I'm sure if it's faster and works just as good then it would be pulled.
  19. Offline


    Milkywayz the problem with that pull request is that the method you want to change, is made for one block. And minecraft is not built for big block changes (excluding things like generation, but those are handles by the NMS classes perfectly fine).

    To point out what WorldEdit is doing (and probably more plugins):
    it calls block.setTypeIdAndData(type, data, false) from CraftBlock.java
    Show Spoiler
    1. public boolean setTypeIdAndData(final int type, final byte data, final boolean applyPhysics) {
    2. if (applyPhysics) {
    3. return chunk.getHandle().world.setTypeIdAndData(x, y, z, type, data);
    4. } else {
    5. boolean success = chunk.getHandle().world.setRawTypeIdAndData(x, y, z, type, data);
    6. if (success) {
    7. chunk.getHandle().world.notify(x, y, z);
    8. }
    9. return success;
    10. }
    11. }

    This calls the NMS's setRawTypeIdAndData(x,y,z,type,data) from World.java
    Show Spoiler
    1. public boolean setRawTypeId(int i, int j, int k, int l) {
    2. if (i >= -30000000 && k >= -30000000 && i < 30000000 && k < 30000000) {
    3. if (j < 0) {
    4. return false;
    5. } else if (j >= 256) {
    6. return false;
    7. } else {
    8. Chunk chunk = this.getChunkAt(i >> 4, k >> 4);
    9. boolean flag = chunk.a(i & 15, j, k & 15, l);
    11. // this.methodProfiler.a("checkLight"); // CraftBukkit - not in production code
    12. this.x(i, j, k);
    13. // this.methodProfiler.b(); // CraftBukkit - not in production code
    14. if (flag && (this.isStatic || chunk.seenByPlayer)) {
    15. this.notify(i, j, k);
    16. }
    18. return flag;
    19. }
    20. } else {
    21. return false;
    22. }
    23. }

    Which ends in a call to the above mentioned a(x, y, z, typeID, data) from Chunk.java and updates the lighting. And if you really need to update the lighting after just calling chunk.a(x, y, z, typeID, data) (mentioned by Timr)
    So what have you completed by changing this? You wrote a method that is actually harder to handle because Bukkit would not know when a plugin wants you to update the lighting.

    In my opinion: if a plugin wants to change a big load of blocks, let them choose to use the Bukkit method, or to use a more direct approach and update the lighting when they need it to update.
  20. Offline


    Well, lighting data is sent as a part of a chunk update (packet 51): http://www.wiki.vg/Protocol#Chunk_Data_.280x33.29 so the server definitely still has a say in what lighting level blocks should have. But, yes, a lot of calculation was moved to the client in 1.2.

    Note also that the NMS World.b(EnumSkyBlock... ) method still has the effect of forcing the light level on a block if called on the server side, but as of 1.2 it's necessary to explicitly send any blocks so changed to the client. See http://forums.bukkit.org/threads/solved-enumskyblock-block-in-1-2-3-r0-1.63780/

    Lighting is frankly a bit of a mess in Minecraft - I've had endless fun(!) getting larger ChessCraft boards to light nicely - the results have never been totally satisfactory. I'm hoping Dinnerbone's changes (planned for 1.4, now pushed to 1.5) make a difference.
  21. Offline


    I do not require any lighting updates, physic's update all I need is the plugin to have a more optimised way of replacing the floor blocks, would it be possible for me to send to plugin to someone and they maybe take a look and try improving it? I would be extremely grateful :D
  22. Offline


    Your best bet would be to loop through the blocks and set them using the method provided by Timr
    for a rectangular/cuboid shape:
    1. public void resetArea(Location a, Location b, int typeID)
    2. {
    3. resetArea(a, b, typeID, 0);
    4. }
    6. public void resetArea(Location a, Location b, int typeID, byte data)
    7. {
    8. Location min, max;
    9. if(a.lengthSquared() > b.lengthSquared())
    10. {
    11. min = b;
    12. max = a;
    13. }
    14. else
    15. {
    16. min = a;
    17. max = b;
    18. }
    19. World w = min.getWorld();
    20. for(int i = min.getX(); i <= max.getX(); i++)
    21. {
    22. for(int j = min.getY(); i <= max.getY(); j++)
    23. {
    24. for(int k = min.getZ(); k <= max.getZ(); k++)
    25. {
    26. setBlockFast(i, j, k, w, typeID, data);
    27. }
    28. }
    29. }
    31. }
    33. public void setBlockFast(int x, int y, int z, World world, int typeID, byte data)
    34. {
    35. Chunk c = world.getChunkAt(x, z);
    36. net.minecraft.server.Chunk chunk = ((CraftChunk) c).getHandle();
    37. chunk.a(x & 15, y, z & 15, typeID, data);
    38. }

    If anyone has remarks, let me know ;3
  23. Offline


    As I said before, the above code will work, but it's only half of the solution; unless updates are sent to the clients (see the thread I linked to before), players won't see any changes (until they re-log).

    Update: actually, your looping logic is flawed there. You're assuming the location closest to the origin has all of X/Y/Z less than the further location's X/Y/Z. That is not necessarily the case. You need to individually compare each co-ordinate for the two locations.

    You're not wrong. WorldEdit is slow at pasting large schematics.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
    Last edited by a moderator: May 29, 2016
  24. Offline


    Could swear WorldEdit used to, obviously not anymore.
Thread Status:
Not open for further replies.

Share This Page