Advertisement
Guest User

PlayerChunkloader class

a guest
Oct 1st, 2011
76
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 10.45 KB | None | 0 0
  1. package com.bergerkiller.bukkit.nolaggchunks;
  2.  
  3. import java.util.HashSet;
  4. import java.util.WeakHashMap;
  5.  
  6. import org.bukkit.Bukkit;
  7. import org.bukkit.World;
  8. import org.bukkit.block.BlockFace;
  9. import org.bukkit.entity.Player;
  10.  
  11. import com.bergerkiller.bukkit.nolagg.ChunkHandler;
  12.  
  13. public class PlayerChunkLoader {
  14.     private static WeakHashMap<Player, PlayerChunkLoader> loaders = new WeakHashMap<Player, PlayerChunkLoader>();
  15.     private static PlayerChunkLoader get(Player player) {
  16.         PlayerChunkLoader loader = loaders.get(player);
  17.         if (loader == null) {
  18.             loader = new PlayerChunkLoader(player);
  19.             int cx = player.getLocation().getBlockX() >> 4;
  20.             int cz = player.getLocation().getBlockX() >> 4;
  21.             loaders.put(player, loader);
  22.             loader.updateChunk(cx, cz, player.getWorld());
  23.         }
  24.         return loader;
  25.     }
  26.    
  27.     private static int taskid = -1;
  28.     private static int rate = 1;
  29.     public static void init(int sendinterval, int sendrate) {
  30.         rate = sendrate;
  31.         if (rate <= 0) return;
  32.         taskid = NoLaggChunks.plugin.getServer().getScheduler().scheduleSyncRepeatingTask(NoLaggChunks.plugin, new Runnable() {
  33.             public void run() {
  34.                 PlayerChunkLoader.sendAll(rate);
  35.             }
  36.         }, 0, sendinterval);
  37.     }
  38.     public static void deinit() {
  39.         if (taskid != -1) {
  40.             NoLaggChunks.plugin.getServer().getScheduler().cancelTask(taskid);
  41.         }
  42.     }
  43.    
  44.    
  45.     public static void clearAll(org.bukkit.Chunk chunk) {
  46.         for (PlayerChunkLoader loader : loaders.values()) {
  47.             loader.clear(chunk);
  48.         }
  49.     }
  50.     public static void clear(Player player, int x, int z) {
  51.         get(player).clear(player.getWorld(), x, z);
  52.     }
  53.     public static void clear(Player player, org.bukkit.Chunk chunk) {
  54.         get(player).clear(chunk);
  55.     }
  56.    
  57.     public static void sendAll(int sendcount) {
  58.         for (Player player : Bukkit.getServer().getOnlinePlayers()) {
  59.             send(player, sendcount);
  60.         }
  61.     }
  62.    
  63.     public static void send(Player player, int sendcount) {
  64.         PlayerChunkLoader loader = get(player);
  65.         loader.send(sendcount, player);
  66.     }
  67.     public static void update(Player player, int newcx, int newcz, World newworld) {
  68.         PlayerChunkLoader loader = get(player);
  69.         loader.updateChunk(newcx, newcz, newworld);
  70.     }
  71.    
  72.     private class Chunk {
  73.         public int x, z;
  74.        
  75.         public Chunk(int x, int z) {
  76.             this.x = x;
  77.             this.z = z;
  78.         }
  79.         public boolean isNear(int x, int z) {
  80.             return Math.abs(this.x - x) <= view && Math.abs(this.z - z) <= view;
  81.         }
  82.         @Override
  83.         public int hashCode() {
  84.             int hash = 3;
  85.             hash = 41 * hash + (this.x ^ (this.x >> 16));
  86.             hash = 41 * hash + (this.z ^ (this.z >> 16));
  87.             return hash;
  88.         }      
  89.         @Override
  90.         public boolean equals(Object object) {
  91.             if (object == this) return true;
  92.             if (object instanceof Chunk) {
  93.                 Chunk c = (Chunk) object;
  94.                 return c.x == this.x && c.z == this.z;
  95.             }
  96.             return false;
  97.         }
  98.     }
  99.    
  100.     private static int view = Bukkit.getServer().getViewDistance();
  101.     private int cx, cz;
  102.     private World world;
  103.     private HashSet<Chunk> sentChunks = new HashSet<Chunk>();
  104.    
  105.     private PlayerChunkLoader(Player player) {
  106.         this.world = player.getWorld();
  107.         this.cx = player.getLocation().getBlockX() >> 4;
  108.         this.cz = player.getLocation().getBlockZ() >> 4;
  109.     }
  110.    
  111.     public static BlockFace getDirection(Player p) {
  112.         int yaw = (int) p.getLocation().getYaw() - 90;
  113.         while (yaw <= -180) yaw += 360;
  114.         while (yaw > 180) yaw -= 360;
  115.         switch ((int) yaw) {
  116.         case 0 : return BlockFace.NORTH;
  117.         case 45 : return BlockFace.NORTH_EAST;
  118.         case 90 : return BlockFace.EAST;
  119.         case 135 : return BlockFace.SOUTH_EAST;
  120.         case 180 : return BlockFace.SOUTH;
  121.         case -135 : return BlockFace.SOUTH_WEST;
  122.         case -90 : return BlockFace.WEST;
  123.         case -45 : return BlockFace.NORTH_WEST;
  124.         }
  125.         //Let's apply angle differences
  126.         if (yaw >= -22.5 && yaw < 22.5) {
  127.             return BlockFace.NORTH;
  128.         } else if (yaw >= 22.5 && yaw < 67.5) {
  129.             return BlockFace.NORTH_EAST;
  130.         } else if (yaw >= 67.5 && yaw < 112.5) {
  131.             return BlockFace.EAST;
  132.         } else if (yaw >= 112.5 && yaw < 157.5) {
  133.             return BlockFace.SOUTH_EAST;
  134.         } else if (yaw >= -67.5 && yaw < -22.5) {
  135.             return BlockFace.NORTH_WEST;
  136.         } else if (yaw >= -112.5 && yaw < -67.5) {
  137.             return BlockFace.WEST;
  138.         } else if (yaw >= -157.5 && yaw < -112.5) {
  139.             return BlockFace.SOUTH_WEST;
  140.         } else {
  141.             return BlockFace.SOUTH;
  142.         }
  143.     }  
  144.    
  145.     public boolean isSent(int cx, int cz) {
  146.         return sentChunks.contains(new Chunk(cx, cz));
  147.     }
  148.    
  149.     private int failedCount = 0;
  150.     public boolean send(int cx, int cz, Player to) {
  151.         if (to != null && !isSent(cx, cz)) {
  152.             NLPacketListener.spoutAllowChunk = true;
  153.             boolean succ = ChunkHandler.send(cx, cz, to);
  154.             NLPacketListener.spoutAllowChunk = false;
  155.             if (succ) {
  156.                 sentChunks.add(new Chunk(cx, cz));
  157.                 return true;
  158.             } else {
  159.                 failedCount++;
  160.                 if (failedCount == 20) {
  161.                     System.out.println("[NoLagg] failed to send 20 chunks to player " + to.getName() + ", the chunk add-on may have to be disabled!");
  162.                     failedCount = 0;
  163.                 }
  164.             }
  165.         }
  166.         return false;
  167.     }
  168.    
  169.     public void clear() {
  170.         sentChunks.clear();
  171.     }
  172.     public void clear(org.bukkit.Chunk chunk) {
  173.         sentChunks.remove(new Chunk(chunk.getX(), chunk.getZ()));
  174.     }
  175.     public void clear(World world, int x, int z) {
  176.         this.clear(world.getChunkAt(x, z));
  177.     }
  178.    
  179.     public void updateChunk(int cx, int cz, World world) {
  180.         if (this.world != world) {
  181.             this.world = world;
  182.             sentChunks.clear();
  183.             this.cx = cx;
  184.             this.cz = cz;
  185.         } else if (cx != this.cx || cz != this.cz) {
  186.             this.cx = cx;
  187.             this.cz = cz;
  188.             //remove chunks no longer visible
  189.             Chunk[] from = sentChunks.toArray(new Chunk[0]);
  190.             Chunk[] sent = new Chunk[from.length];
  191.             for (int i = 0; i < sent.length; i++) {
  192.                 sent[i] = from[i];
  193.             }
  194.             sentChunks.clear();
  195.             for (Chunk c : sent) {
  196.                 if (c.isNear(cx, cz)) {
  197.                     sentChunks.add(c);
  198.                 }
  199.             }
  200.         }
  201.     }
  202.    
  203.     private static class MoveMod {
  204.         private MoveMod(BlockFace direction, boolean right) {
  205.             this.x = direction.getModX();
  206.             this.z = direction.getModZ();
  207.             this.right = right;
  208.         }
  209.        
  210.         public int x;
  211.         public int z;
  212.         public boolean right;
  213.            
  214.         public void next(int midx, int midz, int curx, int curz, int limit) {
  215.             if (Math.abs(midx - curx) == limit && Math.abs(midz - curz) == limit) {
  216.                 if (this.right) {
  217.                     if (x == 1 && z == 0) {
  218.                         z = 1;
  219.                         x = 0;
  220.                     } else if (x == 0 && z == 1) {
  221.                         x = -1;
  222.                         z = 0;
  223.                     } else if (x == -1 && z == 0) {
  224.                         z = -1;
  225.                         x = 0;
  226.                     } else if (x == 0 && z == -1) {
  227.                         x = 1;
  228.                         z = 0;
  229.                     }
  230.                 } else {
  231.                     if (x == 1 && z == 0) {
  232.                         z = -1;
  233.                         x = 0;
  234.                     } else if (x == 0 && z == -1) {
  235.                         x = -1;
  236.                         z = 0;
  237.                     } else if (x == -1 && z == 0) {
  238.                         z = 1;
  239.                         x = 0;
  240.                     } else if (x == 0 && z == 1) {
  241.                         x = 1;
  242.                         z = 0;
  243.                     }
  244.                 }
  245.             }
  246.         }
  247.        
  248.         public static MoveMod[] get(BlockFace direction) {
  249.             MoveMod[] mods = new MoveMod[2];
  250.             if (direction == BlockFace.NORTH) {
  251.                 mods[0] = new MoveMod(BlockFace.WEST, false);
  252.                 mods[1] = new MoveMod(BlockFace.EAST, true);
  253.             } else if (direction == BlockFace.SOUTH) {
  254.                 mods[0] = new MoveMod(BlockFace.WEST, true);
  255.                 mods[1] = new MoveMod(BlockFace.EAST, false);
  256.             } else if (direction == BlockFace.EAST) {
  257.                 mods[0] = new MoveMod(BlockFace.NORTH, false);
  258.                 mods[1] = new MoveMod(BlockFace.SOUTH, true);
  259.             } else if (direction == BlockFace.WEST) {
  260.                 mods[0] = new MoveMod(BlockFace.NORTH, true);
  261.                 mods[1] = new MoveMod(BlockFace.SOUTH, false);
  262.             } else if (direction == BlockFace.NORTH_EAST) {
  263.                 mods[0] = new MoveMod(BlockFace.WEST, false);
  264.                 mods[1] = new MoveMod(BlockFace.SOUTH, true);
  265.             } else if (direction == BlockFace.SOUTH_EAST) {
  266.                 mods[0] = new MoveMod(BlockFace.WEST, true);
  267.                 mods[1] = new MoveMod(BlockFace.NORTH, false);
  268.             } else if (direction == BlockFace.SOUTH_WEST) {
  269.                 mods[0] = new MoveMod(BlockFace.NORTH, true);
  270.                 mods[1] = new MoveMod(BlockFace.EAST, false);
  271.             } else if (direction == BlockFace.NORTH_WEST) {
  272.                 mods[0] = new MoveMod(BlockFace.SOUTH, false);
  273.                 mods[1] = new MoveMod(BlockFace.EAST, true);
  274.             }
  275.             return mods;
  276.         }
  277.        
  278.     }
  279.    
  280.     public int sendLayer(int sendcount, int sendlimit, int layer, BlockFace direction, Player to) {
  281.         //get modifiers from direction
  282.         MoveMod[] mods = MoveMod.get(direction);
  283.         //Get the chunk to start at
  284.         int startx = cx + direction.getModX() * layer;
  285.         int startz = cz + direction.getModZ() * layer;
  286.         //Send starter chunk
  287.         if (this.send(startx, startz, to)) {
  288.             if (--sendcount == 0) return 0;
  289.         }
  290.         //Peel
  291.         int x1 = startx;
  292.         int z1 = startz;
  293.         int x2 = startx;
  294.         int z2 = startz;
  295.         sendlimit++;
  296.         while (true) {
  297.             if (--sendlimit == 0) return sendcount;
  298.             //offset the chunks
  299.             x1 += mods[0].x;
  300.             z1 += mods[0].z;
  301.             x2 += mods[1].x;
  302.             z2 += mods[1].z;
  303.             //mod update
  304.             mods[0].next(cx, cz, x1, z1, layer);
  305.             mods[1].next(cx, cz, x2, z2, layer);
  306.             //got till the end?
  307.             if (x1 == x2 && z1 == z2) {
  308.                 if (this.send(x1, z1, to)) {
  309.                     --sendcount;
  310.                 }
  311.                 return sendcount;
  312.             } else {
  313.                 if (this.send(x1, z1, to)) {
  314.                     if (--sendcount == 0) return 0;
  315.                 }
  316.                 if (this.send(x2, z2, to)) {
  317.                     if (--sendcount == 0) return 0;
  318.                 }
  319.             }
  320.         }
  321.     }
  322.    
  323.     public void send(int sendcount, Player to) {
  324.         send(getDirection(to), sendcount, to);
  325.     }
  326.     public void send(BlockFace direction, int sendcount, Player to) {
  327.         if (sendcount > 0) {
  328.             //main chunk
  329.             if (this.send(cx, cz, to)) {
  330.                 if (--sendcount == 0) return;
  331.             }
  332.            
  333.             final int threshold1 = 3; //to this layer full layers chunks are sent, after half
  334.             final int threshold2 = 5; //at this layer less than half are sent
  335.            
  336.             //full layers
  337.             for (int layer = 1; layer < threshold1; layer++) {
  338.                 sendcount = sendLayer(sendcount, layer * 4, layer, direction, to);
  339.                 if (sendcount == 0) return;
  340.             }
  341.            
  342.             //half layers
  343.             for (int layer = threshold1; layer <= threshold2; layer++) {
  344.                 sendcount = sendLayer(sendcount, (int) (layer * 2), layer, direction, to);
  345.                 if (sendcount == 0) return;
  346.             }
  347.            
  348.             //less than half layers
  349.             for (int layer = threshold2; layer <= view; layer++) {
  350.                 sendcount = sendLayer(sendcount, (int) (layer * 1.5), layer, direction, to);
  351.                 if (sendcount == 0) return;
  352.             }
  353.                        
  354.             //remainder
  355.             for (int a = -view; a <= view; a++) {
  356.                 for (int b = -view; b <= view; b++) {
  357.                     if (this.send(cx + a, cz + b, to)) {
  358.                         if (--sendcount == 0) return;
  359.                     }
  360.                 }
  361.             }
  362.         }
  363.     }
  364.    
  365. }
  366.  
  367.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement